aoqi@0: /* aoqi@0: * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: import com.sun.tools.javac.util.*; aoqi@0: import com.sun.tools.javac.api.*; aoqi@0: import com.sun.tools.javac.file.*; aoqi@0: import java.io.*; aoqi@0: import java.util.*; aoqi@0: import javax.tools.*; aoqi@0: aoqi@0: // More general parameter limit testing framework, and designed so aoqi@0: // that it could be expanded into a general limits-testing framework aoqi@0: // in the future. aoqi@0: public class NumArgsTest { aoqi@0: aoqi@0: private static final NumArgsTest.NestingDef[] NO_NESTING = {}; aoqi@0: aoqi@0: // threshold is named as such because "threshold" args is expected aoqi@0: // to pass, and "threshold" + 1 args is expected to fail. aoqi@0: private final int threshold; aoqi@0: private final boolean isStaticMethod; aoqi@0: private final String result; aoqi@0: private final String testName; aoqi@0: private final String methodName; aoqi@0: private final NestingDef[] nesting; aoqi@0: private final File testdir; aoqi@0: private final JavacTool tool = JavacTool.create(); aoqi@0: private final JavacFileManager fm = aoqi@0: tool.getStandardFileManager(null, null, null); aoqi@0: private int errors = 0; aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final boolean isStaticMethod, aoqi@0: final String result, aoqi@0: final String methodName, aoqi@0: final String testName, aoqi@0: final NestingDef[] nesting) { aoqi@0: this.threshold = threshold; aoqi@0: this.isStaticMethod = isStaticMethod; aoqi@0: this.result = result; aoqi@0: this.methodName = methodName; aoqi@0: this.testName = testName; aoqi@0: this.nesting = nesting; aoqi@0: testdir = new File(testName); aoqi@0: testdir.mkdir(); aoqi@0: } aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final boolean isStaticMethod, aoqi@0: final String result, aoqi@0: final String methodName, aoqi@0: final String testName) { aoqi@0: this(threshold, isStaticMethod, result, methodName, aoqi@0: testName, NO_NESTING); aoqi@0: } aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final String result, aoqi@0: final String methodName, aoqi@0: final String testName, aoqi@0: final NestingDef[] nesting) { aoqi@0: this(threshold, false, result, methodName, testName, nesting); aoqi@0: } aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final String result, aoqi@0: final String methodName, aoqi@0: final String testName) { aoqi@0: this(threshold, false, result, methodName, testName, NO_NESTING); aoqi@0: } aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final String testName, aoqi@0: final NestingDef[] nesting) { aoqi@0: this(threshold, null, null, testName, nesting); aoqi@0: } aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final String testName) { aoqi@0: this(threshold, null, null, testName, NO_NESTING); aoqi@0: } aoqi@0: aoqi@0: public NumArgsTest(final int threshold, aoqi@0: final String testName, aoqi@0: final String constructorName, aoqi@0: final NestingDef[] nesting) { aoqi@0: this(threshold, null, constructorName, testName, nesting); aoqi@0: } aoqi@0: aoqi@0: protected void writeArgs(final int num, final PrintWriter stream) aoqi@0: throws IOException { aoqi@0: stream.print("int x1"); aoqi@0: for(int i = 1; i < num; i++) aoqi@0: stream.print(", int x" + (i + 1)); aoqi@0: } aoqi@0: aoqi@0: protected void writeMethod(final int num, aoqi@0: final String name, aoqi@0: final PrintWriter stream) aoqi@0: throws IOException { aoqi@0: stream.write("public "); aoqi@0: if (isStaticMethod) stream.write("static "); aoqi@0: if (result == null) aoqi@0: stream.write(""); aoqi@0: else { aoqi@0: stream.write(result); aoqi@0: stream.write(" "); aoqi@0: } aoqi@0: stream.write(name); aoqi@0: stream.write("("); aoqi@0: writeArgs(num, stream); aoqi@0: stream.write(") {}\n"); aoqi@0: } aoqi@0: aoqi@0: protected void writeJavaFile(final int num, aoqi@0: final boolean pass, aoqi@0: final PrintWriter stream) aoqi@0: throws IOException { aoqi@0: final String fullName = testName + (pass ? "Pass" : "Fail"); aoqi@0: stream.write("public class "); aoqi@0: stream.write(fullName); aoqi@0: stream.write(" {\n"); aoqi@0: for(int i = 0; i < nesting.length; i++) aoqi@0: nesting[i].writeBefore(stream); aoqi@0: if (null == methodName) aoqi@0: writeMethod(num, fullName, stream); aoqi@0: else aoqi@0: writeMethod(num, methodName, stream); aoqi@0: for(int i = nesting.length - 1; i >= 0; i--) aoqi@0: nesting[i].writeAfter(stream); aoqi@0: stream.write("}\n"); aoqi@0: } aoqi@0: aoqi@0: public void runTest() throws Exception { aoqi@0: // Run the pass test aoqi@0: final String passTestName = testName + "Pass.java"; aoqi@0: final StringWriter passBody = new StringWriter(); aoqi@0: final PrintWriter passStream = new PrintWriter(passBody); aoqi@0: final File passFile = new File(testdir, passTestName); aoqi@0: final FileWriter passWriter = new FileWriter(passFile); aoqi@0: aoqi@0: writeJavaFile(threshold, true, passStream); aoqi@0: passStream.close(); aoqi@0: passWriter.write(passBody.toString()); aoqi@0: passWriter.close(); aoqi@0: aoqi@0: final StringWriter passSW = new StringWriter(); aoqi@0: final String[] passArgs = { passFile.toString() }; aoqi@0: final Iterable passFiles = aoqi@0: fm.getJavaFileObjectsFromFiles(Arrays.asList(passFile)); aoqi@0: final JavaCompiler.CompilationTask passTask = aoqi@0: tool.getTask(passSW, fm, null, null, null, passFiles); aoqi@0: aoqi@0: if (!passTask.call()) { aoqi@0: errors++; aoqi@0: System.err.println("Compilation unexpectedly failed. Body:\n" + aoqi@0: passBody); aoqi@0: System.err.println("Output:\n" + passSW.toString()); aoqi@0: } aoqi@0: aoqi@0: // Run the fail test aoqi@0: final String failTestName = testName + "Fail.java"; aoqi@0: final StringWriter failBody = new StringWriter(); aoqi@0: final PrintWriter failStream = new PrintWriter(failBody); aoqi@0: final File failFile = new File(testdir, failTestName); aoqi@0: final FileWriter failWriter = new FileWriter(failFile); aoqi@0: aoqi@0: writeJavaFile(threshold + 1, false, failStream); aoqi@0: failStream.close(); aoqi@0: failWriter.write(failBody.toString()); aoqi@0: failWriter.close(); aoqi@0: aoqi@0: final StringWriter failSW = new StringWriter(); aoqi@0: final TestDiagnosticHandler failDiag = aoqi@0: new TestDiagnosticHandler("compiler.err.limit.parameters"); aoqi@0: final Iterable failFiles = aoqi@0: fm.getJavaFileObjectsFromFiles(Arrays.asList(failFile)); aoqi@0: final JavaCompiler.CompilationTask failTask = aoqi@0: tool.getTask(failSW, aoqi@0: tool.getStandardFileManager(null, null, null), aoqi@0: failDiag, aoqi@0: null, aoqi@0: null, aoqi@0: failFiles); aoqi@0: aoqi@0: if (failTask.call()) { aoqi@0: errors++; aoqi@0: System.err.println("Compilation unexpectedly succeeded."); aoqi@0: System.err.println("Input:\n" + failBody); aoqi@0: } aoqi@0: aoqi@0: if (!failDiag.sawError) { aoqi@0: errors++; aoqi@0: System.err.println("Did not see expected compile error."); aoqi@0: } aoqi@0: aoqi@0: if (errors != 0) aoqi@0: throw new RuntimeException("Test failed with " + aoqi@0: errors + " errors"); aoqi@0: } aoqi@0: aoqi@0: public static NestingDef classNesting(final String name) { aoqi@0: return new NestedClassBuilder(name, false); aoqi@0: } aoqi@0: aoqi@0: public static NestingDef classNesting(final String name, aoqi@0: final boolean isStatic) { aoqi@0: return new NestedClassBuilder(name, isStatic); aoqi@0: } aoqi@0: aoqi@0: protected interface NestingDef { aoqi@0: public abstract void writeBefore(final PrintWriter stream); aoqi@0: public abstract void writeAfter(final PrintWriter stream); aoqi@0: } aoqi@0: aoqi@0: private static class NestedClassBuilder implements NestingDef { aoqi@0: private final String name; aoqi@0: private final boolean isStatic; aoqi@0: public NestedClassBuilder(final String name, final boolean isStatic) { aoqi@0: this.name = name; aoqi@0: this.isStatic = isStatic; aoqi@0: } aoqi@0: public void writeBefore(final PrintWriter stream) { aoqi@0: stream.write("public "); aoqi@0: if (isStatic) stream.write("static"); aoqi@0: stream.write(" class "); aoqi@0: stream.write(name); aoqi@0: stream.write(" {\n"); aoqi@0: } aoqi@0: public void writeAfter(final PrintWriter stream) { aoqi@0: stream.write("}\n"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public class TestDiagnosticHandler implements DiagnosticListener { aoqi@0: public boolean sawError; aoqi@0: public final String target; aoqi@0: aoqi@0: public TestDiagnosticHandler(final String target) { aoqi@0: this.target = target; aoqi@0: } aoqi@0: aoqi@0: public void report(final Diagnostic diag) { aoqi@0: if (diag.getCode().equals(target)) aoqi@0: sawError = true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: }