1/* 2 * Copyright (c) 2015, 2017, 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 8035473 8154482 8154399 8159096 8176131 8176331 27 * @summary make sure the javadoc tool responds correctly to Xold, 28 * old doclets and taglets. 29 * @library /tools/lib 30 * @build toolbox.ToolBox toolbox.TestRunner 31 * @run main EnsureNewOldDoclet 32 */ 33 34import java.io.*; 35import java.nio.file.Path; 36import java.util.Arrays; 37import java.util.Collections; 38import java.util.List; 39import java.util.Map; 40import java.util.Set; 41import java.util.regex.Pattern; 42import java.util.stream.Collectors; 43import javax.lang.model.element.Element; 44 45import com.sun.javadoc.Tag; 46import com.sun.source.doctree.DocTree; 47 48import toolbox.*; 49 50 51/** 52 * This test ensures the doclet responds correctly when given 53 * various conditions that force a fall back to the old javadoc 54 * tool. The following condition in the order described will 55 * force a dispatch to the old tool, -Xold, old doclet and old taglet. 56 * 57 */ 58public class EnsureNewOldDoclet extends TestRunner { 59 60 final ToolBox tb; 61 final File testSrc; 62 final Path javadocPath; 63 final ExecTask task; 64 final String testClasses; 65 final PrintStream ostream; 66 67 final static String CLASS_NAME = "EnsureNewOldDoclet"; 68 final static String OLD_DOCLET_CLASS_NAME = CLASS_NAME + "$OldDoclet"; 69 final static String NEW_DOCLET_CLASS_NAME = CLASS_NAME + "$NewDoclet"; //unused 70 final static String OLD_TAGLET_CLASS_NAME = CLASS_NAME + "$OldTaglet"; 71 final static String NEW_TAGLET_CLASS_NAME = CLASS_NAME + "$NewTaglet"; 72 73 final static Pattern OLD_HEADER = Pattern.compile("^Standard Doclet \\(Old\\) version.*"); 74 final static Pattern NEW_HEADER = Pattern.compile("^Standard Doclet version.*"); 75 76 77 final static String OLD_DOCLET_MARKER = "OLD_DOCLET_MARKER"; 78 final static String OLD_TAGLET_MARKER = "Registered: OldTaglet"; 79 80 final static String NEW_DOCLET_MARKER = "NEW_DOCLET_MARKER"; 81 final static String NEW_TAGLET_MARKER = "Registered Taglet " + CLASS_NAME + "\\$NewTaglet"; 82 83 final static Pattern WARN_TEXT = Pattern.compile("Users are strongly recommended to migrate" + 84 " to the new APIs."); 85 final static String OLD_DOCLET_ERROR = "java.lang.NoSuchMethodException: " + 86 CLASS_NAME +"\\$NewTaglet"; 87 final static Pattern NEW_DOCLET_ERROR = Pattern.compile(".*java.lang.ClassCastException.*Taglet " + 88 CLASS_NAME + "\\$OldTaglet.*"); 89 90 final static String OLD_STDDOCLET = "com.sun.tools.doclets.standard.Standard"; 91 final static String NEW_STDDOCLET = "jdk.javadoc.doclet.StandardDoclet"; 92 93 94 public EnsureNewOldDoclet() throws Exception { 95 super(System.err); 96 ostream = System.err; 97 testClasses = System.getProperty("test.classes"); 98 tb = new ToolBox(); 99 javadocPath = tb.getJDKTool("javadoc"); 100 task = new ExecTask(tb, javadocPath); 101 testSrc = new File("Foo.java"); 102 generateSample(testSrc); 103 } 104 105 void generateSample(File testSrc) throws Exception { 106 String nl = System.getProperty("line.separator"); 107 String src = Arrays.asList( 108 "/**", 109 " * A test class to test javadoc. Nothing more nothing less.", 110 " */", 111 " public class Foo{}").stream().collect(Collectors.joining(nl)); 112 tb.writeFile(testSrc.getPath(), src); 113 } 114 115 public static void main(String... args) throws Exception { 116 new EnsureNewOldDoclet().runTests(); 117 } 118 119 // input: nothing, default mode 120 // outcome: new tool and new doclet 121 @Test 122 public void testDefault() throws Exception { 123 setArgs("-classpath", ".", // insulates us from ambient classpath 124 testSrc.toString()); 125 Task.Result tr = task.run(Task.Expect.SUCCESS); 126 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 127 checkOutput(testName, out, NEW_HEADER); 128 } 129 130 // input: -Xold 131 // outcome: old tool 132 @Test 133 public void testXold() throws Exception { 134 setArgs("-Xold", 135 "-classpath", ".", // ambient classpath insulation 136 testSrc.toString()); 137 Task.Result tr = task.run(Task.Expect.SUCCESS); 138 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 139 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 140 checkOutput(testName, out, OLD_HEADER); 141 checkOutput(testName, err, WARN_TEXT); 142 } 143 144 // input: old doclet 145 // outcome: old tool 146 @Test 147 public void testOldDoclet() throws Exception { 148 setArgs("-classpath", ".", // ambient classpath insulation 149 "-doclet", 150 OLD_DOCLET_CLASS_NAME, 151 "-docletpath", 152 testClasses, 153 testSrc.toString()); 154 Task.Result tr = task.run(Task.Expect.SUCCESS); 155 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 156 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 157 checkOutput(testName, out, OLD_DOCLET_MARKER); 158 checkOutput(testName, err, WARN_TEXT); 159 } 160 161 // input: old taglet 162 // outcome: old tool 163 @Test 164 public void testOldTaglet() throws Exception { 165 setArgs("-classpath", ".", // ambient classpath insulation 166 "-taglet", 167 OLD_TAGLET_CLASS_NAME, 168 "-tagletpath", 169 testClasses, 170 testSrc.toString()); 171 Task.Result tr = task.run(Task.Expect.SUCCESS); 172 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 173 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 174 checkOutput(testName, out, OLD_TAGLET_MARKER); 175 checkOutput(testName, err, WARN_TEXT); 176 } 177 178 // input: new doclet and old taglet 179 // outcome: new doclet with failure 180 @Test 181 public void testNewDocletOldTaglet() throws Exception { 182 setArgs("-classpath", ".", // ambient classpath insulation 183 "-doclet", 184 NEW_STDDOCLET, 185 "-taglet", 186 OLD_TAGLET_CLASS_NAME, 187 "-tagletpath", 188 testClasses, 189 testSrc.toString()); 190 Task.Result tr = task.run(Task.Expect.FAIL, 1).writeAll(); 191 //Task.Result tr = task.run(); 192 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 193 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 194 checkOutput(testName, out, NEW_HEADER); 195 checkOutput(testName, err, NEW_DOCLET_ERROR); 196 } 197 198 // input: old doclet and old taglet 199 // outcome: old doclet and old taglet should register 200 @Test 201 public void testOldDocletOldTaglet() throws Exception { 202 setArgs("-classpath", ".", // ambient classpath insulation 203 "-doclet", 204 OLD_STDDOCLET, 205 "-taglet", 206 OLD_TAGLET_CLASS_NAME, 207 "-tagletpath", 208 testClasses, 209 testSrc.toString()); 210 Task.Result tr = task.run(Task.Expect.SUCCESS); 211 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 212 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 213 checkOutput(testName, out, OLD_HEADER); 214 checkOutput(testName, out, OLD_TAGLET_MARKER); 215 checkOutput(testName, err, WARN_TEXT); 216 } 217 218 // input: new doclet and new taglet 219 // outcome: new doclet and new taglet should register 220 @Test 221 public void testNewDocletNewTaglet() throws Exception { 222 setArgs("-classpath", ".", // ambient classpath insulation 223 "-doclet", 224 NEW_STDDOCLET, 225 "-taglet", 226 NEW_TAGLET_CLASS_NAME, 227 "-tagletpath", 228 testClasses, 229 testSrc.toString()); 230 Task.Result tr = task.run(Task.Expect.SUCCESS); 231 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 232 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 233 checkOutput(testName, out, NEW_HEADER); 234 checkOutput(testName, out, NEW_TAGLET_MARKER); 235 } 236 237 // input: old doclet and new taglet 238 // outcome: old doclet and error 239 @Test 240 public void testOldDocletNewTaglet() throws Exception { 241 setArgs("-classpath", ".", // ambient classpath insulation 242 "-doclet", 243 OLD_STDDOCLET, 244 "-taglet", 245 NEW_TAGLET_CLASS_NAME, 246 "-tagletpath", 247 testClasses, 248 testSrc.toString()); 249 Task.Result tr = task.run(Task.Expect.FAIL, 1); 250 List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT); 251 List<String> err = tr.getOutputLines(Task.OutputKind.STDERR); 252 checkOutput(testName, out, OLD_HEADER); 253 checkOutput(testName, err, WARN_TEXT); 254 checkOutput(testName, err, OLD_DOCLET_ERROR); 255 } 256 257 void setArgs(String... args) { 258 ostream.println("cmds: " + Arrays.asList(args)); 259 task.args(args); 260 } 261 262 void checkOutput(String testCase, List<String> content, String toFind) throws Exception { 263 checkOutput(testCase, content, Pattern.compile(".*" + toFind + ".*")); 264 } 265 266 void checkOutput(String testCase, List<String> content, Pattern toFind) throws Exception { 267 ostream.println("---" + testCase + "---"); 268 content.stream().forEach(x -> System.out.println(x)); 269 for (String x : content) { 270 ostream.println(x); 271 if (toFind.matcher(x).matches()) { 272 return; 273 } 274 } 275 throw new Exception(testCase + ": Expected string not found: " + toFind); 276 } 277 278 public static class OldDoclet extends com.sun.javadoc.Doclet { 279 public static boolean start(com.sun.javadoc.RootDoc root) { 280 System.out.println(OLD_DOCLET_MARKER); 281 return true; 282 } 283 } 284 285 public static class OldTaglet implements com.sun.tools.doclets.Taglet { 286 287 public static void register(Map map) { 288 EnsureNewOldDoclet.OldTaglet tag = new OldTaglet(); 289 com.sun.tools.doclets.Taglet t = (com.sun.tools.doclets.Taglet) map.get(tag.getName()); 290 System.out.println(OLD_TAGLET_MARKER); 291 } 292 293 @Override 294 public boolean inField() { 295 return true; 296 } 297 298 @Override 299 public boolean inConstructor() { 300 return true; 301 } 302 303 @Override 304 public boolean inMethod() { 305 return true; 306 } 307 308 @Override 309 public boolean inOverview() { 310 return true; 311 } 312 313 @Override 314 public boolean inPackage() { 315 return true; 316 } 317 318 @Override 319 public boolean inType() { 320 return true; 321 } 322 323 @Override 324 public boolean isInlineTag() { 325 return true; 326 } 327 328 @Override 329 public String getName() { 330 return "OldTaglet"; 331 } 332 333 @Override 334 public String toString(Tag tag) { 335 return getName(); 336 } 337 338 @Override 339 public String toString(Tag[] tags) { 340 return getName(); 341 } 342 } 343 344 public static class NewTaglet implements jdk.javadoc.doclet.Taglet { 345 346 @Override 347 public Set<Location> getAllowedLocations() { 348 return Collections.emptySet(); 349 } 350 351 @Override 352 public boolean isInlineTag() { 353 return true; 354 } 355 356 @Override 357 public String getName() { 358 return "NewTaglet"; 359 } 360 361 @Override 362 public String toString(List<? extends DocTree> tags, Element element) { 363 return tags.toString(); 364 } 365 366 } 367} 368