1 /* 2 * Copyright (c) 2012, 2019, 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 import java.io.File; 25 import java.io.IOException; 26 import java.lang.annotation.Annotation; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.net.URI; 32 import java.nio.file.DirectoryStream; 33 import java.nio.file.Files; 34 import java.nio.file.Path; 35 import java.util.Arrays; 36 import java.util.HashSet; 37 import java.util.Set; 38 import java.util.TreeSet; 39 import java.util.stream.*; 40 41 import javax.tools.JavaFileObject; 42 import javax.tools.SimpleJavaFileObject; 43 44 45 /* 46 * Superclass with utility methods for API tests. 47 */ 48 class APITest { 49 protected APITest() { } 50 51 /** Marker annotation for test cases. */ 52 @Retention(RetentionPolicy.RUNTIME) 53 @interface Test { } 54 55 /** Invoke all methods annotated with @Test. */ 56 protected void run() throws Exception { 57 for (Method m: getClass().getDeclaredMethods()) { 58 Annotation a = m.getAnnotation(Test.class); 59 if (a != null) { 60 testCount++; 61 testName = m.getName(); 62 System.err.println("test: " + testName); 63 try { 64 m.invoke(this, new Object[] { }); 65 } catch (InvocationTargetException e) { 66 Throwable cause = e.getCause(); 67 throw (cause instanceof Exception) ? ((Exception) cause) : e; 68 } 69 System.err.println(); 70 } 71 } 72 73 if (testCount == 0) 74 error("no tests found"); 75 76 StringBuilder summary = new StringBuilder(); 77 if (testCount != 1) 78 summary.append(testCount).append(" tests"); 79 if (errorCount > 0) { 80 if (summary.length() > 0) summary.append(", "); 81 summary.append(errorCount).append(" errors"); 82 } 83 System.err.println(summary); 84 if (errorCount > 0) 85 throw new Exception(errorCount + " errors found"); 86 } 87 88 /** 89 * Create a directory in which to store generated doc files. 90 * Avoid using the default (current) directory, so that we can 91 * be sure that javadoc is writing in the intended location, 92 * not a default location. 93 */ 94 protected File getOutDir() { 95 File dir = new File(testName); 96 dir.mkdirs(); 97 return dir; 98 } 99 100 /** 101 * Create a directory in which to store generated doc files. 102 * Avoid using the default (current) directory, so that we can 103 * be sure that javadoc is writing in the intended location, 104 * not a default location. 105 */ 106 protected File getOutDir(String path) { 107 File dir = new File(testName, path); 108 dir.mkdirs(); 109 return dir; 110 } 111 112 protected JavaFileObject createSimpleJavaFileObject() { 113 return createSimpleJavaFileObject("pkg/C", "package pkg; public class C { }"); 114 } 115 116 protected JavaFileObject createSimpleJavaFileObject(final String binaryName, final String content) { 117 return new SimpleJavaFileObject( 118 URI.create("myfo:///" + binaryName + ".java"), JavaFileObject.Kind.SOURCE) { 119 @Override 120 public CharSequence getCharContent(boolean ignoreEncoding) { 121 return content; 122 } 123 }; 124 } 125 126 protected void checkFiles(File dir, Set<String> expectFiles) { 127 Set<File> files = new HashSet<File>(); 128 listFiles(dir, files); 129 Set<String> foundFiles = new HashSet<String>(); 130 URI dirURI = dir.toURI(); 131 for (File f: files) 132 foundFiles.add(dirURI.relativize(f.toURI()).getPath()); 133 checkFiles(foundFiles, expectFiles, dir); 134 } 135 136 protected void checkFiles(Path dir, Set<String> expectFiles) throws IOException { 137 Set<Path> files = new HashSet<Path>(); 138 listFiles(dir, files); 139 Set<String> foundFiles = new HashSet<String>(); 140 for (Path f: files) { 141 foundFiles.add(dir.relativize(f).toString().replace(f.getFileSystem().getSeparator(), "/")); 142 } 143 checkFiles(foundFiles, expectFiles, dir); 144 } 145 146 private void checkFiles(Set<String> foundFiles, Set<String> expectFiles, Object where) { 147 if (!foundFiles.equals(expectFiles)) { 148 Set<String> missing = new TreeSet<String>(expectFiles); 149 missing.removeAll(foundFiles); 150 if (!missing.isEmpty()) 151 error("the following files were not found in " + where + ": " + missing); 152 Set<String> unexpected = new TreeSet<String>(foundFiles); 153 unexpected.removeAll(expectFiles); 154 if (!unexpected.isEmpty()) 155 error("the following unexpected files were found in " + where + ": " + unexpected); 156 } 157 } 158 159 protected void listFiles(File dir, Set<File> files) { 160 for (File f: dir.listFiles()) { 161 if (f.isDirectory()) 162 listFiles(f, files); 163 else if (f.isFile()) 164 files.add(f); 165 } 166 } 167 168 private void listFiles(Path dir, Set<Path> files) throws IOException { 169 try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) { 170 for (Path f: ds) { 171 if (Files.isDirectory(f)) 172 listFiles(f, files); 173 else if (Files.isRegularFile(f)) 174 files.add(f); 175 } 176 } 177 } 178 179 protected void error(String msg) { 180 System.err.println("Error: " + msg); 181 errorCount++; 182 } 183 184 protected int testCount; 185 protected int errorCount; 186 187 protected String testName; 188 189 /** 190 * Standard files generated by processing a documented class pkg.C. 191 */ 192 protected static Set<String> standardExpectFiles = new HashSet<>(Arrays.asList( 193 "allclasses-index.html", 194 "allpackages-index.html", 195 "constant-values.html", 196 "deprecated-list.html", 197 "help-doc.html", 198 "index-all.html", 199 "index.html", 200 "script-dir/jquery-3.4.1.js", 201 "script-dir/jquery-ui.js", 202 "script-dir/jquery-ui.css", 203 "script-dir/jquery-ui.min.js", 204 "script-dir/jquery-ui.min.css", 205 "script-dir/jquery-ui.structure.min.css", 206 "script-dir/jquery-ui.structure.css", 207 "script-dir/external/jquery/jquery.js", 208 "script-dir/images/ui-bg_glass_65_dadada_1x400.png", 209 "script-dir/images/ui-icons_454545_256x240.png", 210 "script-dir/images/ui-bg_glass_95_fef1ec_1x400.png", 211 "script-dir/images/ui-bg_glass_75_dadada_1x400.png", 212 "script-dir/images/ui-bg_highlight-soft_75_cccccc_1x100.png", 213 "script-dir/images/ui-icons_888888_256x240.png", 214 "script-dir/images/ui-icons_2e83ff_256x240.png", 215 "script-dir/images/ui-icons_cd0a0a_256x240.png", 216 "script-dir/images/ui-bg_glass_55_fbf9ee_1x400.png", 217 "script-dir/images/ui-icons_222222_256x240.png", 218 "script-dir/images/ui-bg_glass_75_e6e6e6_1x400.png", 219 "member-search-index.js", 220 "overview-tree.html", 221 "element-list", 222 "package-search-index.js", 223 "pkg/C.html", 224 "pkg/package-summary.html", 225 "pkg/package-tree.html", 226 "resources/glass.png", 227 "resources/x.png", 228 "script.js", 229 "search.js", 230 "stylesheet.css", 231 "system-properties.html", 232 "type-search-index.js" 233 )); 234 235 protected static Set<String> noIndexFiles = standardExpectFiles.stream() 236 .filter(s -> !s.startsWith("script-dir") && !s.startsWith("resources") 237 && !s.equals("index-all.html") && !s.equals("search.js") && !s.endsWith("-search-index.js") 238 && !s.equals("allclasses-index.html") && !s.equals("allpackages-index.html") 239 && !s.equals("system-properties.html")) 240 .collect(Collectors.toSet()); 241 } 242