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.main.Main; 25 import com.sun.tools.javac.util.*; 26 import java.io.*; 27 import javax.tools.JavaFileObject; 28 29 // More general parameter limit testing framework, and designed so 30 // that it could be expanded into a general limits-testing framework 31 // in the future. 32 public class NumArgsTest { 33 34 private int errors = 0; 35 private final int threshold; 36 private final String retty; 37 private final String testName; 38 private final String methodName; 39 private final NestingDef[] nesting; 40 private final File testdir; 41 private static Main compiler = new Main("javac"); 42 43 public NumArgsTest(final int threshold, 44 final String retty, 45 final String methodName, 46 final String testName, 47 final NestingDef[] nesting) { 48 this.threshold = threshold; 49 this.retty = retty; 50 this.methodName = methodName; 51 this.testName = testName; 52 this.nesting = nesting; 53 testdir = new File(testName); 54 testdir.mkdir(); 55 } 56 57 public NumArgsTest(final int threshold, 58 final String testName, 59 final NestingDef[] nesting) { 60 this(threshold, null, null, testName, nesting); 61 } 62 63 public NumArgsTest(final int threshold, 64 final String testName, 65 final String constructorName, 66 final NestingDef[] nesting) { 67 this(threshold, null, constructorName, testName, nesting); 68 } 69 70 protected void writeArgs(final int num, final PrintWriter stream) 71 throws IOException { 72 stream.print("int x1"); 73 for(int i = 1; i < num; i++) 74 stream.print(", int x" + (i + 1)); 75 } 76 77 protected void writeMethod(final int num, 78 final String name, 79 final PrintWriter stream) 80 throws IOException { 81 stream.write("public "); 82 if (retty == null) 83 stream.write(""); 84 else { 85 stream.write(retty); 86 stream.write(" "); 87 } 88 stream.write(name); 89 stream.write("("); 90 writeArgs(num, stream); 91 stream.write(") {}\n"); 92 } 93 94 protected void writeJavaFile(final int num, 95 final boolean pass, 96 final PrintWriter stream) 97 throws IOException { 98 final String fullName = testName + (pass ? "Pass" : "Fail"); 99 stream.write("public class "); 100 stream.write(fullName); 101 stream.write(" {\n"); 102 for(int i = 0; i < nesting.length; i++) 103 nesting[i].writeBefore(stream); 104 if (null == methodName) 105 writeMethod(num, fullName, stream); 106 else 107 writeMethod(num, methodName, stream); 108 for(int i = nesting.length - 1; i >= 0; i--) 109 nesting[i].writeAfter(stream); 110 stream.write("}\n"); 111 } 112 113 public void runTest() throws Exception { 114 // Run the pass test 115 final String passTestName = testName + "Pass.java"; 116 final StringWriter passBody = new StringWriter(); 117 final PrintWriter passStream = new PrintWriter(passBody); 118 final File passFile = new File(testdir, passTestName); 119 final FileWriter passWriter = new FileWriter(passFile); 120 121 writeJavaFile(threshold, true, passStream); 122 passStream.close(); 123 passWriter.write(passBody.toString()); 124 passWriter.close(); 125 126 final StringWriter passSW = new StringWriter(); 127 final PrintWriter passPW = new PrintWriter(passSW); 128 final Main passCompiler = new Main("javac", passPW); 129 final Context passContext = new Context(); 130 final Log passLog = Log.instance(passContext); 131 final TestDiagnosticHandler passDiag = 132 new TestDiagnosticHandler(passLog, "limit.parameters"); 133 final String[] passArgs = { passFile.toString() }; 134 final Main.Result passResult = 135 passCompiler.compile(passArgs, null, passContext, 136 List.<JavaFileObject>nil(), null, passLog); 137 138 passPW.close(); 139 140 if(passResult.exitCode != 0) { 141 errors++; 142 System.err.println("Compilation unexpectedly failed. Body:\n" + 143 passBody); 144 System.err.println("Output:\n" + passSW.toString()); 145 } 146 147 // Run the fail test 148 final String failTestName = testName + "Fail.java"; 149 final StringWriter failBody = new StringWriter(); 150 final PrintWriter failStream = new PrintWriter(failBody); 151 final File failFile = new File(testdir, failTestName); 152 final FileWriter failWriter = new FileWriter(failFile); 153 154 writeJavaFile(threshold + 1, false, failStream); 155 failStream.close(); 156 failWriter.write(failBody.toString()); 157 failWriter.close(); 158 159 final StringWriter failSW = new StringWriter(); 160 final PrintWriter failPW = new PrintWriter(failSW); 161 final Main failCompiler = new Main("javac", failPW); 162 final Context failContext = new Context(); 163 final Log failLog = Log.instance(failContext); 164 final TestDiagnosticHandler failDiag = 165 new TestDiagnosticHandler(failLog, "compiler.err.limit.parameters"); 166 final String[] failArgs = { failFile.toString() }; 167 final Main.Result failResult = 168 failCompiler.compile(failArgs, null, failContext, 169 List.<JavaFileObject>nil(), null, failLog); 170 171 failPW.close(); 172 173 if(failResult.exitCode == 0) { 174 errors++; 175 System.err.println("Compilation unexpectedly succeeded."); 176 System.err.println("Input:\n" + failBody); 177 } 178 179 if (!failDiag.sawError) { 180 errors++; 181 System.err.println("Did not see expected compile error."); 182 } 183 184 if (errors != 0) 185 throw new RuntimeException("Test failed with " + 186 errors + " errors"); 187 } 188 189 public static NestingDef classNesting(final String name) { 190 return new ClassNestingDef(name, false); 191 } 192 193 public static NestingDef classNesting(final String name, 194 final boolean isStatic) { 195 return new ClassNestingDef(name, isStatic); 196 } 197 198 protected interface NestingDef { 199 public abstract void writeBefore(final PrintWriter stream); 200 public abstract void writeAfter(final PrintWriter stream); 201 } 202 203 private static class ClassNestingDef implements NestingDef { 204 private final String name; 205 private final boolean isStatic; 206 public ClassNestingDef(final String name, final boolean isStatic) { 207 this.name = name; 208 this.isStatic = isStatic; 209 } 210 public void writeBefore(final PrintWriter stream) { 211 stream.write("public "); 212 if (isStatic) stream.write("static"); 213 stream.write(" class "); 214 stream.write(name); 215 stream.write(" {\n"); 216 } 217 public void writeAfter(final PrintWriter stream) { 218 stream.write("}\n"); 219 } 220 } 221 222 public class TestDiagnosticHandler extends Log.DiagnosticHandler { 223 public boolean sawError; 224 public final String target; 225 226 public TestDiagnosticHandler(final Log log, final String target) { 227 install(log); 228 this.target = target; 229 } 230 231 public void report(final JCDiagnostic diag) { 232 if (diag.getCode().equals(target)) 233 sawError = true; 234 prev.report(diag); 235 } 236 } 237 238 }