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