1/*
2 * Copyright (c) 2014, 2015, 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
24import java.io.IOException;
25import java.io.OutputStream;
26import java.io.UncheckedIOException;
27import java.lang.annotation.Annotation;
28import java.lang.annotation.Retention;
29import java.lang.annotation.RetentionPolicy;
30import java.lang.reflect.InvocationTargetException;
31import java.lang.reflect.Method;
32import java.nio.file.FileSystem;
33import java.nio.file.FileSystems;
34import java.nio.file.Files;
35import java.nio.file.Path;
36import java.nio.file.Paths;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.List;
40import java.util.stream.Collectors;
41import java.util.zip.ZipEntry;
42import java.util.zip.ZipOutputStream;
43
44import javax.tools.JavaCompiler;
45import javax.tools.StandardJavaFileManager;
46import javax.tools.ToolProvider;
47
48/**
49 * Base class for unit tests for StandardJavaFileManager.
50 */
51class SJFM_TestBase {
52
53    /** Shared compiler instance. */
54    JavaCompiler comp;
55
56    /** A list of items to be closed when the test is complete. */
57    List<AutoCloseable> closeables;
58
59    /**
60     * Runs a test. This is the primary entry point and should generally be
61     * called from each test's main method.
62     * It calls all methods annotated with {@code @Test} with the instances
63     * of StandardJavaFileManager to be tested.
64     *
65     * @throws Exception if the test fails.
66     */
67    void run() throws Exception {
68        comp = ToolProvider.getSystemJavaCompiler();
69        closeables = new ArrayList<>();
70
71        try (StandardJavaFileManager systemFileManager = comp.getStandardFileManager(null, null, null);
72                StandardJavaFileManager customFileManager = new MyStandardJavaFileManager(systemFileManager)) {
73            test(systemFileManager);
74            test(customFileManager);
75        } finally {
76            for (AutoCloseable c: closeables) {
77                try {
78                    c.close();
79                } catch (IOException e) {
80                    error("Exception closing " + c + ": " + e);
81                }
82            }
83        }
84
85        if (errors > 0)
86            throw new Exception(errors + " errors occurred");
87    }
88
89    /**
90     * Get the file managers to be tested.
91     *
92     * Currently, two are provided:
93     * <ol>
94     * <li>the system-provided file manager
95     * <li>a custom file manager, which relies on the default methods provided in the
96     *     StandardJavaFileManager interface
97     * </li>
98     *
99     * @return the file managers to be tested
100     */
101    List<StandardJavaFileManager> getTestFileManagers() {
102        StandardJavaFileManager systemFileManager = comp.getStandardFileManager(null, null, null);
103        StandardJavaFileManager customFileManager = new MyStandardJavaFileManager(systemFileManager);
104        return Arrays.asList(systemFileManager, customFileManager);
105    }
106
107    /**
108     * Tests a specific file manager, by calling all methods annotated
109     * with {@code @Test} passing this file manager as an argument.
110     *
111     * @param fm the file manager to be tested
112     * @throws Exception if the test fails
113     */
114    void test(StandardJavaFileManager fm) throws Exception {
115        System.err.println("Testing " + fm);
116        for (Method m: getClass().getDeclaredMethods()) {
117            Annotation a = m.getAnnotation(Test.class);
118            if (a != null) {
119                try {
120                    System.err.println("Test " + m.getName());
121                    m.invoke(this, new Object[] { fm });
122                } catch (InvocationTargetException e) {
123                    Throwable cause = e.getCause();
124                    throw (cause instanceof Exception) ? ((Exception) cause) : e;
125                }
126                System.err.println();
127            }
128        }
129    }
130
131    /** Marker annotation for test cases. */
132    @Retention(RetentionPolicy.RUNTIME)
133    @interface Test { }
134
135    /**
136     * Returns a series of paths for artifacts in the default file system.
137     * The paths are for the .java files in the test.src directory.
138     *
139     * @return a list of paths
140     * @throws IOException
141     */
142    List<Path> getTestFilePaths() throws IOException {
143        String testSrc = System.getProperty("test.src");
144        return Files.list(Paths.get(testSrc))
145                .filter(p -> p.getFileName().toString().endsWith(".java"))
146                .collect(Collectors.toList());
147    }
148
149    private FileSystem zipfs;
150    private List<Path> zipPaths;
151
152    /**
153     * Returns a series of paths for artifacts in a non-default file system.
154     * A zip file is created containing copies of the .java files in the
155     * test.src directory. The paths that are returned refer to these files.
156     *
157     * @return a list of paths
158     * @throws IOException
159     */
160    List<Path> getTestZipPaths() throws IOException {
161        if (zipfs == null) {
162            Path testZip = createSourceZip();
163            zipfs = FileSystems.newFileSystem(testZip, null);
164            closeables.add(zipfs);
165            zipPaths = Files.list(zipfs.getRootDirectories().iterator().next())
166                .filter(p -> p.getFileName().toString().endsWith(".java"))
167                .collect(Collectors.toList());
168        }
169        return zipPaths;
170    }
171
172    /**
173     * Create a zip file containing the contents of the test.src directory.
174     *
175     * @return a path for the zip file.
176     * @throws IOException if there is a problem creating the file
177     */
178    private Path createSourceZip() throws IOException {
179        Path testSrc = Paths.get(System.getProperty("test.src"));
180        Path testZip = Paths.get("test.zip");
181        try (OutputStream os = Files.newOutputStream(testZip)) {
182            try (ZipOutputStream zos = new ZipOutputStream(os)) {
183                Files.list(testSrc)
184                    .filter(p -> p.getFileName().toString().endsWith(".java"))
185                    .forEach(p -> {
186                        try {
187                            zos.putNextEntry(new ZipEntry(p.getFileName().toString()));
188                            zos.write(Files.readAllBytes(p));
189                            zos.closeEntry();
190                        } catch (IOException ex) {
191                            throw new UncheckedIOException(ex);
192                        }
193                    });
194            }
195        }
196        return testZip;
197    }
198
199    /**
200     * Tests whether it is expected that a file manager will be able
201     * to create a series of file objects from a series of paths.
202     *
203     * MyStandardJavaFileManager does not support paths referring to
204     * non-default file systems.
205     *
206     * @param fm  the file manager to be tested
207     * @param paths  the paths to be tested
208     * @return
209     */
210    boolean isGetFileObjectsSupported(StandardJavaFileManager fm, List<Path> paths) {
211        return !(fm instanceof MyStandardJavaFileManager
212                && (paths.get(0).getFileSystem() != FileSystems.getDefault()));
213    }
214
215    /**
216     * Report an error.
217     */
218    void error(String msg) {
219        System.err.println("Error: " + msg);
220        errors++;
221    }
222
223    /** Count of errors reported. */
224    int errors;
225
226}
227