NumArgsTest.java revision 3294:9adfb22ff08f
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
24import com.sun.tools.javac.api.*;
25import com.sun.tools.javac.file.*;
26import java.io.*;
27import java.util.*;
28import 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.
33public 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
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
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
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
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
91    public NumArgsTest(final int threshold,
92                       final String testName,
93                       final NestingDef[] nesting) {
94        this(threshold, null, null, testName, nesting);
95    }
96
97    public NumArgsTest(final int threshold,
98                       final String testName) {
99        this(threshold, null, null, testName, NO_NESTING);
100    }
101
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
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
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
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
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
221    public static NestingDef classNesting(final String name) {
222        return new NestedClassBuilder(name, false);
223    }
224
225    public static NestingDef classNesting(final String name,
226                                          final boolean isStatic) {
227        return new NestedClassBuilder(name, isStatic);
228    }
229
230    protected interface NestingDef {
231        public abstract void writeBefore(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;
238        public NestedClassBuilder(final String name, final boolean isStatic) {
239            this.name = name;
240            this.isStatic = isStatic;
241        }
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        }
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
258        public TestDiagnosticHandler(final String target) {
259            this.target = target;
260        }
261
262        public void report(final Diagnostic<? extends T> diag) {
263            if (diag.getCode().equals(target))
264                sawError = true;
265        }
266    }
267
268}
269