1 /* 2 * Copyright (c) 2013, 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 com.sun.tools.javac.util.*; 25 import com.sun.tools.javac.api.*; 26 import com.sun.tools.javac.file.*; 27 import java.io.*; 28 import java.util.*; 29 import javax.tools.*; 30 31 // More general parameter limit testing framework, and designed so 32 // that it could be expanded into a general limits-testing framework 33 // in the future. 34 public class NumArgsTest { 35 36 private static final NumArgsTest.NestingDef[] NO_NESTING = {}; 37 38 // threshold is named a such because "threshold" args is expected 39 // to pass, and "threshold" + 1 args is expected to fail. 40 private final int threshold; 41 private final boolean isStaticMethod; 42 private final String result; 43 private final String testName; 44 private final String methodName; 45 private final NestingDef[] nesting; 46 private final File testdir; 47 private final JavacTool tool = JavacTool.create(); 48 private final JavacFileManager fm = 49 tool.getStandardFileManager(null, null, null); 50 private int errors = 0; 51 52 public NumArgsTest(final int threshold, 53 final boolean isStaticMethod, 54 final String result, 55 final String methodName, 56 final String testName, 57 final NestingDef[] nesting) { 58 this.threshold = threshold; 59 this.isStaticMethod = isStaticMethod; 60 this.result = result; 61 this.methodName = methodName; 62 this.testName = testName; 63 this.nesting = nesting; 64 testdir = new File(testName); 65 testdir.mkdir(); 66 } 67 68 public NumArgsTest(final int threshold, 69 final boolean isStaticMethod, 70 final String result, 71 final String methodName, 72 final String testName) { 73 this(threshold, isStaticMethod, result, methodName, 74 testName, NO_NESTING); 75 } 76 77 public NumArgsTest(final int threshold, 78 final String result, 79 final String methodName, 80 final String testName, 81 final NestingDef[] nesting) { 82 this(threshold, false, result, methodName, testName, nesting); 83 } 84 85 public NumArgsTest(final int threshold, 86 final String result, 87 final String methodName, 88 final String testName) { 89 this(threshold, false, result, methodName, testName, NO_NESTING); 90 } 91 92 public NumArgsTest(final int threshold, 93 final String testName, 94 final NestingDef[] nesting) { 95 this(threshold, null, null, testName, nesting); 96 } 97 98 public NumArgsTest(final int threshold, 99 final String testName) { 100 this(threshold, null, null, testName, NO_NESTING); 101 } 102 103 public NumArgsTest(final int threshold, 104 final String testName, 105 final String constructorName, 106 final NestingDef[] nesting) { 107 this(threshold, null, constructorName, testName, nesting); 108 } 109 110 protected void writeArgs(final int num, final PrintWriter stream) 111 throws IOException { 112 stream.print("int x1"); 113 for(int i = 1; i < num; i++) 114 stream.print(", int x" + (i + 1)); 115 } 116 117 protected void writeMethod(final int num, 118 final String name, 119 final PrintWriter stream) 120 throws IOException { 121 stream.write("public "); 122 if (isStaticMethod) stream.write("static "); 123 if (result == null) 124 stream.write(""); 125 else { 126 stream.write(result); 127 stream.write(" "); 128 } 129 stream.write(name); 130 stream.write("("); 131 writeArgs(num, stream); 132 stream.write(") {}\n"); 133 } 134 135 protected void writeJavaFile(final int num, 136 final boolean pass, 137 final PrintWriter stream) 138 throws IOException { 139 final String fullName = testName + (pass ? "Pass" : "Fail"); 140 stream.write("public class "); 141 stream.write(fullName); 142 stream.write(" {\n"); 143 for(int i = 0; i < nesting.length; i++) 144 nesting[i].writeBefore(stream); 145 if (null == methodName) 146 writeMethod(num, fullName, stream); 147 else 148 writeMethod(num, methodName, stream); 149 for(int i = nesting.length - 1; i >= 0; i--) 150 nesting[i].writeAfter(stream); 151 stream.write("}\n"); 152 } 153 154 public void runTest() throws Exception { 155 // Run the pass test 156 final String passTestName = testName + "Pass.java"; 157 final StringWriter passBody = new StringWriter(); 158 final PrintWriter passStream = new PrintWriter(passBody); 159 final File passFile = new File(testdir, passTestName); 160 final FileWriter passWriter = new FileWriter(passFile); 161 162 writeJavaFile(threshold, true, passStream); 163 passStream.close(); 164 passWriter.write(passBody.toString()); 165 passWriter.close(); 166 167 final StringWriter passSW = new StringWriter(); 168 final String[] passArgs = { passFile.toString() }; 169 final Iterable<? extends JavaFileObject> passFiles = 170 fm.getJavaFileObjectsFromFiles(Arrays.asList(passFile)); 171 final JavaCompiler.CompilationTask passTask = 172 tool.getTask(passSW, fm, null, null, null, passFiles); 173 174 if (!passTask.call()) { 175 errors++; 176 System.err.println("Compilation unexpectedly failed. Body:\n" + 177 passBody); 178 System.err.println("Output:\n" + passSW.toString()); 179 } 180 181 // Run the fail test 182 final String failTestName = testName + "Fail.java"; 183 final StringWriter failBody = new StringWriter(); 184 final PrintWriter failStream = new PrintWriter(failBody); 185 final File failFile = new File(testdir, failTestName); 186 final FileWriter failWriter = new FileWriter(failFile); 187 188 writeJavaFile(threshold + 1, false, failStream); 189 failStream.close(); 190 failWriter.write(failBody.toString()); 191 failWriter.close(); 192 193 final StringWriter failSW = new StringWriter(); 194 final TestDiagnosticHandler failDiag = 195 new TestDiagnosticHandler("compiler.err.limit.parameters"); 196 final Iterable<? extends JavaFileObject> failFiles = 197 fm.getJavaFileObjectsFromFiles(Arrays.asList(failFile)); 198 final JavaCompiler.CompilationTask failTask = 199 tool.getTask(failSW, 200 tool.getStandardFileManager(null, null, null), 201 failDiag, 202 null, 203 null, 204 failFiles); 205 206 if (failTask.call()) { 207 errors++; 208 System.err.println("Compilation unexpectedly succeeded."); 209 System.err.println("Input:\n" + failBody); 210 } 211 212 if (!failDiag.sawError) { 213 errors++; 214 System.err.println("Did not see expected compile error."); 215 } 216 217 if (errors != 0) 218 throw new RuntimeException("Test failed with " + 219 errors + " errors"); 220 } 221 222 public static NestingDef classNesting(final String name) { 223 return new NestedClassBuilder(name, false); 224 } 225 226 public static NestingDef classNesting(final String name, 227 final boolean isStatic) { 228 return new NestedClassBuilder(name, isStatic); 229 } 230 231 protected interface NestingDef { 232 public abstract void writeBefore(final PrintWriter stream); 233 public abstract void writeAfter(final PrintWriter stream); 234 } 235 236 private static class NestedClassBuilder implements NestingDef { 237 private final String name; 238 private final boolean isStatic; 239 public NestedClassBuilder(final String name, final boolean isStatic) { 240 this.name = name; 241 this.isStatic = isStatic; 242 } 243 public void writeBefore(final PrintWriter stream) { 244 stream.write("public "); 245 if (isStatic) stream.write("static"); 246 stream.write(" class "); 247 stream.write(name); 248 stream.write(" {\n"); 249 } 250 public void writeAfter(final PrintWriter stream) { 251 stream.write("}\n"); 252 } 253 } 254 255 public class TestDiagnosticHandler<T> implements DiagnosticListener<T> { 256 public boolean sawError; 257 public final String target; 258 259 public TestDiagnosticHandler(final String target) { 260 this.target = target; 261 } 262 263 public void report(final Diagnostic<? extends T> diag) { 264 if (diag.getCode().equals(target)) 265 sawError = true; 266 } 267 } 268 269 }