ModuleTestBase.java revision 3595:81692f730015
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
24import java.io.IOException;
25import java.io.PrintWriter;
26import java.io.StringWriter;
27import java.nio.file.Path;
28import java.nio.file.Paths;
29import java.util.Arrays;
30import java.util.Collections;
31import java.util.List;
32import java.util.Locale;
33import java.util.Set;
34import java.util.TreeSet;
35
36import javax.lang.model.SourceVersion;
37import javax.lang.model.element.Element;
38import javax.lang.model.element.ElementKind;
39import javax.lang.model.element.ModuleElement;
40import javax.lang.model.element.PackageElement;
41import javax.lang.model.element.TypeElement;
42import javax.lang.model.util.ElementFilter;
43import javax.lang.model.util.SimpleElementVisitor9;
44
45import jdk.javadoc.doclet.Doclet;
46import jdk.javadoc.doclet.DocletEnvironment;
47import jdk.javadoc.doclet.Reporter;
48
49import toolbox.JavadocTask;
50import toolbox.Task;
51import toolbox.Task.Expect;
52import toolbox.TestRunner;
53import toolbox.ToolBox;
54
55import static toolbox.Task.OutputKind.*;
56
57/**
58 * Base class for module tests.
59 */
60public class ModuleTestBase extends TestRunner {
61
62    // Field Separator
63    private static final String FS = " ";
64
65    protected ToolBox tb;
66    private final Class<?> docletClass;
67
68    private Task.Result currentTask = null;
69
70    ModuleTestBase() {
71        super(System.err);
72        tb = new ToolBox();
73        ClassLoader cl = ModuleTestBase.class.getClassLoader();
74        try {
75            docletClass = cl.loadClass("ModuleTestBase$ModulesTesterDoclet");
76        } catch (ClassNotFoundException cfe) {
77            throw new Error(cfe);
78        }
79    }
80
81    /**
82     * Execute methods annotated with @Test, and throw an exception if any
83     * errors are reported..
84     *
85     * @throws Exception if any errors occurred
86     */
87    protected void runTests() throws Exception {
88        runTests(m -> new Object[] { Paths.get(m.getName()) });
89    }
90
91    Task.Result execTask(String... args) {
92        return execTask0(false, args);
93    }
94
95    Task.Result execNegativeTask(String... args) {
96        return execTask0(true, args);
97    }
98
99    private Task.Result execTask0(boolean isNegative, String... args) {
100        JavadocTask et = new JavadocTask(tb, Task.Mode.API);
101        et.docletClass(docletClass);
102        //Arrays.asList(args).forEach((a -> System.err.println("arg: " + a)));
103        System.err.println(Arrays.asList(args));
104        currentTask = isNegative
105                ? et.options(args).run(Expect.FAIL)
106                : et.options(args).run();
107        return currentTask;
108    }
109
110    Path[] findHtmlFiles(Path... paths) throws IOException {
111        return tb.findFiles(".html", paths);
112    }
113
114    boolean grep(String regex, Path file) throws Exception {
115        List<String> lines = tb.readAllLines(file);
116        List<String> foundList = tb.grep(regex, lines);
117        return !foundList.isEmpty();
118    }
119
120    String normalize(String in) {
121        return in.replace('\\', '/');
122    }
123
124    void checkModulesSpecified(String... args) throws Exception {
125        for (String arg : args) {
126            checkDocletOutputPresent("Specified", ElementKind.MODULE, arg);
127        }
128    }
129
130    void checkPackagesSpecified(String... args) throws Exception {
131        for (String arg : args) {
132            checkDocletOutputPresent("Specified", ElementKind.PACKAGE, arg);
133        }
134    }
135
136    void checkTypesSpecified(String... args) throws Exception {
137        for (String arg : args) {
138            checkDocletOutputPresent("Specified", ElementKind.CLASS, arg);
139        }
140    }
141
142    void checkModulesIncluded(String... args) throws Exception {
143        for (String arg : args) {
144            checkDocletOutputPresent("Included", ElementKind.MODULE, arg);
145        }
146    }
147
148    void checkPackagesIncluded(String... args) throws Exception {
149        for (String arg : args) {
150            checkDocletOutputPresent("Included", ElementKind.PACKAGE, arg);
151        }
152    }
153
154    void checkTypesIncluded(String... args) throws Exception {
155        for (String arg : args) {
156            checkDocletOutputPresent("Included", ElementKind.CLASS, arg);
157        }
158    }
159
160    void checkMembersSelected(String... args) throws Exception {
161        for (String arg : args) {
162            checkDocletOutputPresent("Selected", ElementKind.METHOD, arg);
163        }
164    }
165
166    void checkModuleMode(String mode) throws Exception {
167        assertPresent("^ModuleMode" + FS + mode);
168    }
169
170    void checkStringPresent(String regex) throws Exception {
171        assertPresent(regex);
172    }
173
174    void checkDocletOutputPresent(String category, ElementKind kind, String regex) throws Exception {
175        assertPresent("^" + category + " " + kind.toString() + " " + regex);
176    }
177
178    void assertPresent(String regex) throws Exception {
179        assertPresent(regex, STDOUT);
180    }
181
182    void assertErrorPresent(String regex) throws Exception {
183        assertPresent(regex, Task.OutputKind.DIRECT);
184    }
185
186    void assertPresent(String regex, Task.OutputKind kind) throws Exception {
187        List<String> foundList = tb.grep(regex, currentTask.getOutputLines(kind));
188        if (foundList.isEmpty()) {
189            dumpDocletDiagnostics();
190            throw new Exception(regex + " not found in: " + kind);
191        }
192    }
193
194    void dumpDocletDiagnostics() {
195        for (Task.OutputKind kind : Task.OutputKind.values()) {
196            String output = currentTask.getOutput(kind);
197            if (output != null && !output.isEmpty()) {
198                System.err.println("<" + kind + ">");
199                System.err.println(output);
200            }
201        }
202    }
203
204    void checkModulesNotSpecified(String... args) throws Exception {
205        for (String arg : args) {
206            checkDocletOutputAbsent("Specified", ElementKind.MODULE, arg);
207        }
208    }
209
210    void checkPackagesNotSpecified(String... args) throws Exception {
211        for (String arg : args) {
212            checkDocletOutputAbsent("Specified", ElementKind.PACKAGE, arg);
213        }
214    }
215
216    void checkTypesNotSpecified(String... args) throws Exception {
217        for (String arg : args) {
218            checkDocletOutputAbsent("Specified", ElementKind.CLASS, arg);
219        }
220    }
221
222    void checkModulesNotIncluded(String... args) throws Exception {
223        for (String arg : args) {
224            checkDocletOutputAbsent("Included", ElementKind.MODULE, arg);
225        }
226    }
227
228    void checkPackagesNotIncluded(String... args) throws Exception {
229        for (String arg : args) {
230            checkDocletOutputAbsent("Included", ElementKind.PACKAGE, arg);
231        }
232    }
233
234    void checkTypesNotIncluded(String... args) throws Exception {
235        for (String arg : args) {
236            checkDocletOutputAbsent("Included", ElementKind.CLASS, arg);
237        }
238    }
239
240    void checkMembersNotSelected(String... args) throws Exception {
241        for (String arg : args) {
242            checkDocletOutputAbsent("Selected", ElementKind.METHOD, arg);
243        }
244    }
245
246    void checkStringAbsent(String regex) throws Exception {
247        assertAbsent(regex);
248    }
249
250    void checkDocletOutputAbsent(String category, ElementKind kind, String regex) throws Exception {
251        assertAbsent("^" + category + FS + kind.toString() + FS + regex);
252    }
253
254    void assertAbsent(String regex) throws Exception {
255        List<String> foundList = tb.grep(regex, currentTask.getOutputLines(STDOUT));
256        if (!foundList.isEmpty()) {
257            dumpDocletDiagnostics();
258            throw new Exception(regex + " found in: " + STDOUT);
259        }
260    }
261
262    public static class ModulesTesterDoclet implements Doclet {
263        StringWriter sw = new StringWriter();
264        PrintWriter ps = new PrintWriter(sw);
265
266        // csv style output, for simple regex verification
267        void printDataSet(String header, Set<? extends Element> set) {
268            for (Element e : set) {
269                ps.print(header);
270                new SimpleElementVisitor9<Void, Void>() {
271                    @Override
272                    public Void visitModule(ModuleElement e, Void p) {
273                        ps.print(FS);
274                        ps.print(e.getKind());
275                        ps.print(FS);
276                        ps.println(e.getQualifiedName());
277                        return null;
278                    }
279
280                    @Override
281                    public Void visitPackage(PackageElement e, Void p) {
282                        ps.print(FS);
283                        ps.print(e.getKind());
284                        ps.print(FS);
285                        ps.println(e.getQualifiedName());
286                        return null;
287                    }
288
289                    @Override
290                    public Void visitType(TypeElement e, Void p) {
291                        ps.print(FS);
292                        ps.print(ElementKind.CLASS);
293                        ps.print(FS);
294                        ps.println(e.getQualifiedName());
295                        return null;
296                    }
297
298                    @Override
299                    protected Void defaultAction(Element e, Void p) {
300                        Element encl = e.getEnclosingElement();
301                        CharSequence fqn = new SimpleElementVisitor9<CharSequence, Void>() {
302                            @Override
303                            public CharSequence visitModule(ModuleElement e, Void p) {
304                                return e.getQualifiedName();
305                            }
306
307                            @Override
308                            public CharSequence visitType(TypeElement e, Void p) {
309                                return e.getQualifiedName();
310                            }
311
312                            @Override
313                            public CharSequence visitPackage(PackageElement e, Void p) {
314                                return e.getQualifiedName();
315                            }
316
317                        }.visit(encl);
318
319                        ps.print(FS);
320                        ps.print(ElementKind.METHOD); // always METHOD
321                        ps.print(FS);
322                        ps.print(fqn);
323                        ps.print(".");
324                        ps.println(e.getSimpleName());
325                        return null;
326                    }
327                }.visit(e);
328            }
329        }
330
331        @Override
332        public boolean run(DocletEnvironment docenv) {
333            ps.println("ModuleMode" + FS + docenv.getModuleMode());
334            printDataSet("Specified", docenv.getSpecifiedElements());
335            printDataSet("Included", docenv.getIncludedModuleElements());
336            printDataSet("Included", docenv.getIncludedPackageElements());
337            printDataSet("Included", docenv.getIncludedTypeElements());
338            printDataSet("Selected", getAllSelectedElements(docenv));
339            System.out.println(sw);
340            return true;
341        }
342
343        Set<Element> getAllSelectedElements(DocletEnvironment docenv) {
344            Set<Element> result = new TreeSet<Element>((Element e1, Element e2) -> {
345                // some grouping by kind preferred
346                int rc = e1.getKind().compareTo(e2.getKind());
347                if (rc != 0) return rc;
348                rc = e1.toString().compareTo(e2.toString());
349                if (rc != 0) return rc;
350                return Integer.compare(e1.hashCode(), e2.hashCode());
351            });
352            for (ModuleElement me : docenv.getIncludedModuleElements()) {
353                addEnclosedElements(docenv, result, me);
354            }
355            for (PackageElement pe : docenv.getIncludedPackageElements()) {
356                addEnclosedElements(docenv, result, docenv.getElementUtils().getModuleOf(pe));
357                addEnclosedElements(docenv, result, pe);
358            }
359            for (TypeElement te : docenv.getIncludedTypeElements()) {
360                addEnclosedElements(docenv, result, te);
361            }
362            return result;
363        }
364
365        void addEnclosedElements(DocletEnvironment docenv, Set<Element> result, Element e) {
366            List<? extends Element> elems = docenv.getSelectedElements(e.getEnclosedElements());
367            result.addAll(elems);
368            for (TypeElement t : ElementFilter.typesIn(elems)) {
369                addEnclosedElements(docenv, result, t);
370            }
371        }
372
373        @Override
374        public Set<Doclet.Option> getSupportedOptions() {
375            return Collections.emptySet();
376        }
377
378        @Override
379        public void init(Locale locale, Reporter reporter) {}
380
381        @Override
382        public String getName() {
383            return "ModulesTesterDoclet";
384        }
385
386        @Override
387        public SourceVersion getSupportedSourceVersion() {
388            return SourceVersion.latest();
389        }
390    }
391}
392