TestFilerConstraints.java revision 1465:b52a38d4536c
1/*
2 * Copyright (c) 2006, 2010, 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/*
25 * @test
26 * @bug 6380018 6453386 6457283
27 * @summary Test that the constraints guaranteed by the Filer and maintained
28 * @author  Joseph D. Darcy
29 * @library /tools/javac/lib
30 * @build TestFilerConstraints
31 * @compile -encoding iso-8859-1 -processor TestFilerConstraints -proc:only TestFilerConstraints.java
32 */
33
34import java.util.Set;
35import javax.annotation.processing.*;
36import javax.lang.model.SourceVersion;
37import static javax.lang.model.SourceVersion.*;
38import javax.lang.model.element.*;
39import javax.lang.model.util.*;
40import static javax.lang.model.util.ElementFilter.*;
41import static javax.tools.Diagnostic.Kind.*;
42import static javax.tools.StandardLocation.*;
43
44import java.io.*;
45import java.nio.charset.Charset;
46
47/**
48 * A processor that verifies the explicit and implicit constraints in
49 * the Filer contract are maintained:
50 *
51 * <blockquote>
52 *
53 *  During each run of an annotation processing tool, a file with a
54 *  given pathname may be created only once. If that file already
55 *  exists before the first attempt to create it, the old contents
56 *  will be deleted. Any subsequent attempt to create the same file
57 *  during a run will throw a FilerException, as will attempting to
58 *  open both a class file and source file for the same type name.
59 *
60 * </blockquote>
61 *
62 * Specific checks will include:
63 *
64 * <ul>
65 *
66 * <li> Source and class files can be written to from either a Writer or an OutputStream.
67 *
68 * <li> Calling close multiple times does not re-register the file for
69 * processing.
70 *
71 * </ul>
72 */
73public class TestFilerConstraints extends JavacTestingAbstractProcessor {
74    private int round = 0;
75
76    private PrintWriter  pw_src1 = null;
77    private PrintWriter  pw_src2 = null;
78    private OutputStream os_classFile1 = null;
79    private      Writer  pw_classFile2 = null;
80
81    public boolean process(Set<? extends TypeElement> annotations,
82                           RoundEnvironment roundEnv) {
83        round++;
84
85        try {
86            switch(round) {
87                // Open two source files
88            case 1:
89                pw_src1 = new PrintWriter(filer.createSourceFile("Src1").openWriter());
90                pw_src1.println("class Src1 {}");
91                pw_src1.close();
92
93                // Hold open across rounds
94                pw_src2 = new PrintWriter(new OutputStreamWriter(filer.createSourceFile("Src2").openOutputStream()));
95                break;
96
97            case 2:
98                testExpectedType(roundEnv, "Src1");
99
100                // Close Src1 a second time
101                pw_src1.close();
102
103                pw_src2.println("class Src2 {}");
104                pw_src2.close();
105
106                break;
107
108            case 3:
109                testExpectedType(roundEnv, "Src2");
110
111                // Close Src2 a second time
112                pw_src2.close();
113
114                os_classFile1 = filer.createClassFile("ClassFile1").openOutputStream();
115                for (int value : classFile1Bytes)
116                    os_classFile1.write((byte)value);
117                os_classFile1.close();
118
119                break;
120
121            case 4:
122                testExpectedType(roundEnv, "ClassFile1");
123
124                // Close a second time
125                os_classFile1.close();
126
127                testReopening();
128
129                pw_classFile2 = new PrintWriter(filer.createClassFile("ClassFile2",
130                                                                      (Element[])null).openWriter());
131
132                for(int byteVal : classFile2Bytes) {
133                    // int value = (0xff00 & (classFile2Bytes[i]<<8)) | classFile2Bytes[i+1];
134                    // System.out.print(Integer.toHexString(value));
135                    //if ((i % 4) == 0)
136                    // System.out.println();
137                    pw_classFile2.write((char) (0xff & byteVal));
138                }
139                pw_classFile2.close();
140
141                break;
142
143
144
145            case 5:
146                testExpectedType(roundEnv, "ClassFile2");
147                // Close a second time
148                pw_classFile2.close();
149
150
151                break;
152
153            case 6:
154                if (!roundEnv.processingOver() && !roundEnv.errorRaised())
155                    throw new RuntimeException("Bad round state: " + roundEnv);
156                break;
157
158            default:
159                throw new RuntimeException("Unexpected round number!");
160            }
161        } catch (IOException ioe) {
162            throw new RuntimeException(ioe);
163        }
164
165        return true;
166    }
167
168    /**
169     * Test that the single expected expected type, name, is the root
170     * element.
171     */
172    private void testExpectedType(RoundEnvironment roundEnv, String name) {
173        if (!roundEnv.getRootElements().isEmpty()) {
174            for(TypeElement type : typesIn(roundEnv.getRootElements())) {
175                if (!name.contentEquals(type.getSimpleName()))
176                    throw new RuntimeException("Unexpected type " +  type.getSimpleName());
177            }
178        } else
179            throw new RuntimeException("Unexpected empty root elements.");
180    }
181
182    private void testReopening() throws IOException {
183        String[] names = {"Src1", "Src2", "ClassFile1"};
184        for (String name : names) {
185            try {
186                filer.createSourceFile(name);
187                throw new RuntimeException("Opened a source file for type " + name);
188            } catch (FilerException fe) {;}
189
190            try {
191                filer.createClassFile(name);
192                throw new RuntimeException("Opened a class file for type " + name);
193            } catch (FilerException fe) {;}
194        }
195
196        // Try to open a resource over a source file
197        try {
198            filer.createResource(SOURCE_OUTPUT, "", "Src1.java");
199            throw new RuntimeException("Opened a text file over Src1.java!");
200        } catch (FilerException fe) {;}
201
202        // Try to open a resource over a class file
203        try {
204            filer.createResource(CLASS_OUTPUT, "", "ClassFile1.class");
205            throw new RuntimeException("Opened a text file over Src1.java!");
206        } catch (FilerException fe) {;}
207
208    }
209
210    private int[] classFile1Bytes =
211    {202, 254, 186, 190,   0,   0,   0,  50,
212       0,  13,  10,   0,   3,   0,  10,   7,
213       0,  11,   7,   0,  12,   1,   0,   6,
214      60, 105, 110, 105, 116,  62,   1,   0,
215       3,  40,  41,  86,   1,   0,   4,  67,
216     111, 100, 101,   1,   0,  15,  76, 105,
217     110, 101,  78, 117, 109,  98, 101, 114,
218      84,  97,  98, 108, 101,   1,   0,  10,
219      83, 111, 117, 114,  99, 101,  70, 105,
220     108, 101,   1,   0,  15,  67, 108,  97,
221     115, 115,  70, 105, 108, 101,  49,  46,
222     106,  97, 118,  97,  12,   0,   4,   0,
223       5,   1,   0,  10,  67, 108,  97, 115,
224     115,  70, 105, 108, 101,  49,   1,   0,
225      16, 106,  97, 118,  97,  47, 108,  97,
226     110, 103,  47,  79,  98, 106, 101,  99,
227     116,   0,  33,   0,   2,   0,   3,   0,
228       0,   0,   0,   0,   1,   0,   1,   0,
229       4,   0,   5,   0,   1,   0,   6,   0,
230       0,   0,  29,   0,   1,   0,   1,   0,
231       0,   0,   5,  42, 183,   0,   1, 177,
232       0,   0,   0,   1,   0,   7,   0,   0,
233       0,   6,   0,   1,   0,   0,   0,   1,
234       0,   1,   0,   8,   0,   0,   0,   2,
235       0,   9,};
236
237    private int[] classFile2Bytes =
238    {202, 254, 186, 190,   0,   0,   0,  50,
239       0,  13,  10,   0,   3,   0,  10,   7,
240       0,  11,   7,   0,  12,   1,   0,   6,
241      60, 105, 110, 105, 116,  62,   1,   0,
242       3,  40,  41,  86,   1,   0,   4,  67,
243     111, 100, 101,   1,   0,  15,  76, 105,
244     110, 101,  78, 117, 109,  98, 101, 114,
245      84,  97,  98, 108, 101,   1,   0,  10,
246      83, 111, 117, 114,  99, 101,  70, 105,
247     108, 101,   1,   0,  15,  67, 108,  97,
248     115, 115,  70, 105, 108, 101,  50,  46,
249     106,  97, 118,  97,  12,   0,   4,   0,
250       5,   1,   0,  10,  67, 108,  97, 115,
251     115,  70, 105, 108, 101,  50,   1,   0,
252      16, 106,  97, 118,  97,  47, 108,  97,
253     110, 103,  47,  79,  98, 106, 101,  99,
254     116,   0,  33,   0,   2,   0,   3,   0,
255       0,   0,   0,   0,   1,   0,   1,   0,
256       4,   0,   5,   0,   1,   0,   6,   0,
257       0,   0,  29,   0,   1,   0,   1,   0,
258       0,   0,   5,  42, 183,   0,   1, 177,
259       0,   0,   0,   1,   0,   7,   0,   0,
260       0,   6,   0,   1,   0,   0,   0,   1,
261       0,   1,   0,   8,   0,   0,   0,   2,
262       0,   9,};
263}
264