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