| /* | |
| * 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; | |
| } | |
| } | |
| } |