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