|
1 /* |
|
2 * Copyright (c) 2015, 2016, 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 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 |
|
27 * @summary Test SourceCodeAnalysis |
|
28 * @build KullaTesting TestingInputStream |
|
29 * @run testng CompletenessTest |
|
30 */ |
|
31 |
|
32 import java.util.Map; |
|
33 import java.util.HashMap; |
|
34 |
|
35 import org.testng.annotations.Test; |
|
36 import jdk.jshell.SourceCodeAnalysis.Completeness; |
|
37 |
|
38 import static jdk.jshell.SourceCodeAnalysis.Completeness.*; |
|
39 |
|
40 @Test |
|
41 public class CompletenessTest extends KullaTesting { |
|
42 |
|
43 // Add complete units that end with semicolon to complete_with_semi (without |
|
44 // the semicolon). Both cases will be tested. |
|
45 static final String[] complete = new String[] { |
|
46 "{ x= 4; }", |
|
47 "int mm(int x) {kll}", |
|
48 "if (t) { ddd; }", |
|
49 "for (int i = 0; i < lines.length(); ++i) { foo }", |
|
50 "while (ct == null) { switch (current.kind) { case EOF: { } } }", |
|
51 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched); }", |
|
52 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); }", |
|
53 "List<T> f() { return null; }", |
|
54 "List<?> f() { return null; }", |
|
55 "List<? extends Object> f() { return null; }", |
|
56 "Map<? extends Object, ? super Object> f() { return null; }", |
|
57 "class C { int z; }", |
|
58 "synchronized (r) { f(); }", |
|
59 "try { } catch (Exception ex) { }", |
|
60 "try { } catch (Exception ex) { } finally { }", |
|
61 "try { } finally { }", |
|
62 "try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)) { }", |
|
63 "foo: while (true) { printf(\"Innn\"); break foo; }", |
|
64 "class Case<E1 extends Enum<E1>, E2 extends Enum<E2>, E3 extends Enum<E3>> {}", |
|
65 ";", |
|
66 "enum Tt { FOO, BAR, BAZ,; }" |
|
67 }; |
|
68 |
|
69 static final String[] expression = new String[] { |
|
70 "test", |
|
71 "x + y", |
|
72 "x + y ++", |
|
73 "p = 9", |
|
74 "match(BRACKETS, TokenKind.LBRACKET)", |
|
75 "new C()", |
|
76 "new C() { public String toString() { return \"Hi\"; } }", |
|
77 "new int[]", |
|
78 "new int[] {1, 2,3}", |
|
79 "new Foo() {}", |
|
80 "i >= 0 && Character.isWhitespace(s.charAt(i))", |
|
81 "int.class", |
|
82 "String.class", |
|
83 }; |
|
84 |
|
85 static final String[] complete_with_semi = new String[] { |
|
86 "int mm", |
|
87 "if (t) ddd", |
|
88 "int p = 9", |
|
89 "int p", |
|
90 "Deque<Token> stack = new ArrayDeque<>()", |
|
91 "final Deque<Token> stack = new ArrayDeque<>()", |
|
92 "java.util.Scanner input = new java.util.Scanner(System.in)", |
|
93 "java.util.Scanner input = new java.util.Scanner(System.in) { }", |
|
94 "int j = -i", |
|
95 "String[] a = { \"AAA\" }", |
|
96 "assert true", |
|
97 "int path[]", |
|
98 "int path[][]", |
|
99 "int path[][] = new int[22][]", |
|
100 "int path[] = new int[22]", |
|
101 "int path[] = new int[] {1, 2, 3}", |
|
102 "int[] path", |
|
103 "int path[] = new int[22]", |
|
104 "int path[][] = new int[22][]", |
|
105 "for (Object o : a) System.out.println(\"Yep\")", |
|
106 "while (os == null) System.out.println(\"Yep\")", |
|
107 "do f(); while (t)", |
|
108 "if (os == null) System.out.println(\"Yep\")", |
|
109 "if (t) if (!t) System.out.println(123)", |
|
110 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else break", |
|
111 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else continue", |
|
112 "for (int i = 0; i < 10; ++i) if (i < 5) System.out.println(i); else return", |
|
113 "throw ex", |
|
114 "C c = new C()", |
|
115 "java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)", |
|
116 "BufferedReader br = new BufferedReader(new FileReader(path))", |
|
117 "bar: g()", |
|
118 "baz: while (true) if (t()) printf('-'); else break baz", |
|
119 "java.util.function.IntFunction<int[]> ggg = int[]::new", |
|
120 "List<? extends Object> l", |
|
121 "int[] m = {1, 2}", |
|
122 "int[] m = {1, 2}, n = null", |
|
123 "int[] m = {1, 2}, n", |
|
124 "int[] m = {1, 2}, n = {3, 4}", |
|
125 }; |
|
126 |
|
127 static final String[] considered_incomplete = new String[] { |
|
128 "if (t)", |
|
129 "if (t) { } else", |
|
130 "if (t) if (!t)", |
|
131 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE))", |
|
132 "for (int i = 0; i < 10; ++i)", |
|
133 "while (os == null)", |
|
134 }; |
|
135 |
|
136 static final String[] definitely_incomplete = new String[] { |
|
137 "int mm(", |
|
138 "int mm(int x", |
|
139 "int mm(int x)", |
|
140 "int mm(int x) {", |
|
141 "int mm(int x) {kll", |
|
142 "if", |
|
143 "if (", |
|
144 "if (t", |
|
145 "if (t) {", |
|
146 "if (t) { ddd", |
|
147 "if (t) { ddd;", |
|
148 "if (t) if (", |
|
149 "if (stack.isEmpty()) {", |
|
150 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) {", |
|
151 "if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched);", |
|
152 "x +", |
|
153 "x *", |
|
154 "3 *", |
|
155 "int", |
|
156 "for (int i = 0; i < lines.length(); ++i) {", |
|
157 "new", |
|
158 "new C(", |
|
159 "new int[", |
|
160 "new int[] {1, 2,3", |
|
161 "new int[] {", |
|
162 "while (ct == null) {", |
|
163 "while (ct == null) { switch (current.kind) {", |
|
164 "while (ct == null) { switch (current.kind) { case EOF: {", |
|
165 "while (ct == null) { switch (current.kind) { case EOF: { } }", |
|
166 "enum TK {", |
|
167 "enum TK { EOF(TokenKind.EOF, 0),", |
|
168 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)", |
|
169 "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ", |
|
170 "enum Tt { FOO, BAR, BAZ,;", |
|
171 "class C", |
|
172 "class C extends D", |
|
173 "class C implements D", |
|
174 "class C implements D, E", |
|
175 "interface I extends D", |
|
176 "interface I extends D, E", |
|
177 "enum E", |
|
178 "enum E implements I1", |
|
179 "enum E implements I1, I2", |
|
180 "@interface Anno", |
|
181 "void f()", |
|
182 "void f() throws E", |
|
183 "@A(", |
|
184 "int n = 4,", |
|
185 "int n,", |
|
186 "int[] m = {1, 2},", |
|
187 "int[] m = {1, 2}, n = {3, 4},", |
|
188 "Map<String," |
|
189 }; |
|
190 |
|
191 static final String[] unknown = new String[] { |
|
192 "new ;" |
|
193 }; |
|
194 |
|
195 static final Map<Completeness, String[]> statusToCases = new HashMap<>(); |
|
196 static { |
|
197 statusToCases.put(COMPLETE, complete); |
|
198 statusToCases.put(COMPLETE_WITH_SEMI, complete_with_semi); |
|
199 statusToCases.put(CONSIDERED_INCOMPLETE, considered_incomplete); |
|
200 statusToCases.put(DEFINITELY_INCOMPLETE, definitely_incomplete); |
|
201 } |
|
202 |
|
203 private void assertStatus(String input, Completeness status, String source) { |
|
204 String augSrc; |
|
205 switch (status) { |
|
206 case COMPLETE_WITH_SEMI: |
|
207 augSrc = source + ";"; |
|
208 break; |
|
209 |
|
210 case DEFINITELY_INCOMPLETE: |
|
211 augSrc = null; |
|
212 break; |
|
213 |
|
214 case CONSIDERED_INCOMPLETE: |
|
215 augSrc = source + ";"; |
|
216 break; |
|
217 |
|
218 case EMPTY: |
|
219 case COMPLETE: |
|
220 case UNKNOWN: |
|
221 augSrc = source; |
|
222 break; |
|
223 |
|
224 default: |
|
225 throw new AssertionError(); |
|
226 } |
|
227 assertAnalyze(input, status, augSrc); |
|
228 } |
|
229 |
|
230 private void assertStatus(String[] ins, Completeness status) { |
|
231 for (String input : ins) { |
|
232 assertStatus(input, status, input); |
|
233 } |
|
234 } |
|
235 |
|
236 public void test_complete() { |
|
237 assertStatus(complete, COMPLETE); |
|
238 } |
|
239 |
|
240 public void test_expression() { |
|
241 assertStatus(expression, COMPLETE); |
|
242 } |
|
243 |
|
244 public void test_complete_with_semi() { |
|
245 assertStatus(complete_with_semi, COMPLETE_WITH_SEMI); |
|
246 } |
|
247 |
|
248 public void test_considered_incomplete() { |
|
249 assertStatus(considered_incomplete, CONSIDERED_INCOMPLETE); |
|
250 } |
|
251 |
|
252 public void test_definitely_incomplete() { |
|
253 assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); |
|
254 } |
|
255 |
|
256 public void test_unknown() { |
|
257 assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); |
|
258 } |
|
259 |
|
260 public void testCompleted_complete_with_semi() { |
|
261 for (String in : complete_with_semi) { |
|
262 String input = in + ";"; |
|
263 assertStatus(input, COMPLETE, input); |
|
264 } |
|
265 } |
|
266 |
|
267 public void testCompleted_expression_with_semi() { |
|
268 for (String in : expression) { |
|
269 String input = in + ";"; |
|
270 assertStatus(input, COMPLETE, input); |
|
271 } |
|
272 } |
|
273 |
|
274 public void testCompleted_considered_incomplete() { |
|
275 for (String in : considered_incomplete) { |
|
276 String input = in + ";"; |
|
277 assertStatus(input, COMPLETE, input); |
|
278 } |
|
279 } |
|
280 |
|
281 private void assertSourceByStatus(String first) { |
|
282 for (Map.Entry<Completeness, String[]> e : statusToCases.entrySet()) { |
|
283 for (String in : e.getValue()) { |
|
284 String input = first + in; |
|
285 assertAnalyze(input, COMPLETE, first, in, true); |
|
286 } |
|
287 } |
|
288 } |
|
289 |
|
290 public void testCompleteSource_complete() { |
|
291 for (String input : complete) { |
|
292 assertSourceByStatus(input); |
|
293 } |
|
294 } |
|
295 |
|
296 public void testCompleteSource_complete_with_semi() { |
|
297 for (String in : complete_with_semi) { |
|
298 String input = in + ";"; |
|
299 assertSourceByStatus(input); |
|
300 } |
|
301 } |
|
302 |
|
303 public void testCompleteSource_expression() { |
|
304 for (String in : expression) { |
|
305 String input = in + ";"; |
|
306 assertSourceByStatus(input); |
|
307 } |
|
308 } |
|
309 |
|
310 public void testCompleteSource_considered_incomplete() { |
|
311 for (String in : considered_incomplete) { |
|
312 String input = in + ";"; |
|
313 assertSourceByStatus(input); |
|
314 } |
|
315 } |
|
316 |
|
317 public void testTrailingSlash() { |
|
318 assertStatus("\"abc\\", UNKNOWN, "\"abc\\"); |
|
319 } |
|
320 |
|
321 public void testOpenComment() { |
|
322 assertStatus("int xx; /* hello", DEFINITELY_INCOMPLETE, null); |
|
323 assertStatus("/** test", DEFINITELY_INCOMPLETE, null); |
|
324 } |
|
325 |
|
326 public void testMiscSource() { |
|
327 assertStatus("if (t) if ", DEFINITELY_INCOMPLETE, "if (t) if"); //Bug |
|
328 assertStatus("int m() {} dfd", COMPLETE, "int m() {}"); |
|
329 assertStatus("int p = ", DEFINITELY_INCOMPLETE, "int p ="); //Bug |
|
330 assertStatus("int[] m = {1, 2}, n = new int[0]; int i;", COMPLETE, |
|
331 "int[] m = {1, 2}, n = new int[0];"); |
|
332 } |
|
333 } |