1 /*
2  * Copyright (c) 2017, 2018, 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 8177076 8185426 8189595 8188072 8221759
27  * @modules
28  *     jdk.compiler/com.sun.tools.javac.api
29  *     jdk.compiler/com.sun.tools.javac.main
30  *     jdk.jshell/jdk.internal.jshell.tool
31  *     jdk.jshell/jdk.internal.jshell.tool.resources:open
32  *     jdk.jshell/jdk.jshell:open
33  * @library /tools/lib
34  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask
35  * @build Compiler UITesting
36  * @build ToolTabSnippetTest
37  * @run testng/timeout=300 ToolTabSnippetTest
38  */
39 
40 import java.io.IOException;
41 import java.lang.reflect.Field;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.nio.file.Paths;
45 import java.util.Arrays;
46 import java.util.concurrent.CountDownLatch;
47 import java.util.jar.JarEntry;
48 import java.util.jar.JarOutputStream;
49 
50 import jdk.internal.jshell.tool.ConsoleIOContextTestSupport;
51 import org.testng.annotations.Test;
52 
53 @Test
54 public class ToolTabSnippetTest extends UITesting {
55 
ToolTabSnippetTest()56     public ToolTabSnippetTest() {
57         super(true);
58     }
59 
testExpression()60     public void testExpression() throws Exception {
61         Path classes = prepareZip();
62         doRunTest((inputSink, out) -> {
63             inputSink.write("/env -class-path " + classes.toString() + "\n");
64             waitOutput(out, resource("jshell.msg.set.restore") + "\n\\u001B\\[\\?2004h" + PROMPT);
65             inputSink.write("import jshelltest.*;\n");
66             waitOutput(out, "\n\\u001B\\[\\?2004l\\u001B\\[\\?2004h" + PROMPT);
67 
68             //-> <tab>
69             inputSink.write(TAB);
70             waitOutput(out, getMessage("jshell.console.completion.all.completions.number", "[0-9]+"));
71             inputSink.write(TAB);
72             waitOutput(out, ".*String.*StringBuilder.*" +
73                             REDRAW_PROMPT + "");
74 
75             //new JShellTes<tab>
76             inputSink.write("new JShellTes" + TAB);
77             waitOutput(out, "\nJShellTest\\(      JShellTestAux\\(   " +
78                             REDRAW_PROMPT + "new JShellTest");
79 
80             //new JShellTest<tab>
81             inputSink.write(TAB);
82             waitOutput(out, "JShellTest\\(      JShellTestAux\\(   \n" +
83                             "\n" +
84                             resource("jshell.console.completion.current.signatures") + "\n" +
85                             "jshelltest.JShellTest\n" +
86                             "\n" +
87                             resource("jshell.console.see.documentation") +
88                             REDRAW_PROMPT + "new JShellTest");
89             inputSink.write(TAB);
90             waitOutput(out, "\\u001B\\[1mjshelltest.JShellTest\\u001B\\[0m\n" +
91                             "JShellTest 0" +
92                             REDRAW_PROMPT + "new JShellTest");
93             inputSink.write(TAB);
94             waitOutput(out, "JShellTest\\(      JShellTestAux\\(   \n" +
95                             "\n" +
96                             resource("jshell.console.completion.current.signatures") + "\n" +
97                             "jshelltest.JShellTest\n" +
98                             "\n" +
99                             resource("jshell.console.see.documentation") +
100                             REDRAW_PROMPT + "new JShellTest");
101 
102             //new JShellTest(<tab>
103             inputSink.write("(" + TAB);
104             waitOutput(out, "\\(\n" +
105                             resource("jshell.console.completion.current.signatures") + "\n" +
106                             "JShellTest\\(String str\\)\n" +
107                             "JShellTest\\(String str, int i\\)\n" +
108                             "\n" +
109                             resource("jshell.console.see.documentation") +
110                             REDRAW_PROMPT + "new JShellTest\\(");
111             inputSink.write(TAB);
112             waitOutput(out, "\\u001B\\[1mJShellTest\\(String str\\)\\u001B\\[0m\n" +
113                             "JShellTest 1\n" +
114                             "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
115                             "\n" +
116                             resource("jshell.console.see.next.page") +
117                             REDRAW_PROMPT + "new JShellTest\\(");
118             inputSink.write(TAB);
119             waitOutput(out, "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
120                             "\n" +
121                             resource("jshell.console.see.next.javadoc") +
122                             REDRAW_PROMPT + "new JShellTest\\(");
123             inputSink.write(TAB);
124             waitOutput(out, "\\u001B\\[1mJShellTest\\(String str, int i\\)\\u001B\\[0m\n" +
125                             "JShellTest 2\n" +
126                             "\n" +
127                             getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
128                             REDRAW_PROMPT + "new JShellTest\\(");
129             inputSink.write(TAB);
130             waitOutput(out, ".*String.*StringBuilder.*" +
131                             REDRAW_PROMPT + "new JShellTest\\(");
132 
133             inputSink.write(INTERRUPT + "String str = \"\";\nnew JShellTest(");
134             waitOutput(out, PROMPT + "new JShellTest\\(");
135 
136             inputSink.write(TAB);
137             waitOutput(out, "\n" +
138                             "str   \n" +
139                             "\n" +
140                             resource("jshell.console.completion.current.signatures") + "\n" +
141                             "JShellTest\\(String str\\)\n" +
142                             "JShellTest\\(String str, int i\\)\n" +
143                             "\n" +
144                             resource("jshell.console.see.documentation") +
145                             REDRAW_PROMPT + "new JShellTest\\(");
146             inputSink.write(TAB);
147             waitOutput(out, "\\u001B\\[1mJShellTest\\(String str\\)\\u001B\\[0m\n" +
148                             "JShellTest 1\n" +
149                             "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
150                             "\n" +
151                             resource("jshell.console.see.next.page") +
152                             REDRAW_PROMPT + "new JShellTest\\(");
153             inputSink.write(TAB);
154             waitOutput(out, "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
155                             "\n" +
156                             resource("jshell.console.see.next.javadoc") +
157                             REDRAW_PROMPT + "new JShellTest\\(");
158             inputSink.write(TAB);
159             waitOutput(out, "\\u001B\\[1mJShellTest\\(String str, int i\\)\\u001B\\[0m\n" +
160                             "JShellTest 2\n" +
161                             "\n" +
162                             getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
163                             REDRAW_PROMPT + "new JShellTest\\(");
164             inputSink.write(TAB);
165             waitOutput(out, ".*String.*StringBuilder.*" +
166                             REDRAW_PROMPT + "new JShellTest\\(");
167 
168             inputSink.write(INTERRUPT + "JShellTest t = new JShellTest" + TAB);
169             waitOutput(out, PROMPT + "JShellTest t = new JShellTest\n" +
170                             "JShellTest\\(   \n" +
171                             "\n" +
172                             resource("jshell.console.completion.current.signatures") + "\n" +
173                             "jshelltest.JShellTest\n" +
174                             "\n" +
175                             resource("jshell.console.completion.all.completions") +
176                             REDRAW_PROMPT + "JShellTest t = new JShellTest");
177             inputSink.write(TAB);
178             waitOutput(out, "JShellTest\\(      JShellTestAux\\(   \n" +
179                             "\n" +
180                             resource("jshell.console.see.documentation") +
181                             REDRAW_PROMPT + "JShellTest t = new JShellTest");
182 
183             inputSink.write(INTERRUPT + "JShellTest t = new " + TAB);
184             waitOutput(out, PROMPT + "JShellTest t = new \n" +
185                             "JShellTest\\(   \n" +
186                             "\n" +
187                             getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
188                             REDRAW_PROMPT + "JShellTest t = new ");
189             inputSink.write(TAB);
190             waitOutput(out, ".*String.*StringBuilder.*" +
191                             REDRAW_PROMPT + "JShellTest t = new ");
192 
193             inputSink.write(INTERRUPT + "class JShelX{}\n");
194             inputSink.write("new JShel" + TAB);
195             waitOutput(out, PROMPT + "new JShel\n" +
196                             "JShelX\\(\\)         JShellTest\\(      JShellTestAux\\(   " +
197                             REDRAW_PROMPT + "new JShel");
198 
199             //no crash:
200             inputSink.write(INTERRUPT + "new Stringbuil" + TAB);
201             waitOutput(out, PROMPT + "new Stringbuil" + BELL);
202 
203             //no crash: 8188072
204             inputSink.write(INTERRUPT + "for (int:" + TAB);
205             waitOutput(out, PROMPT + "for \\(int:\n" +
206                             getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
207                             REDRAW_PROMPT + "for \\(int:");
208         });
209     }
210 
testCleaningCompletionTODO()211     public void testCleaningCompletionTODO() throws Exception {
212         doRunTest((inputSink, out) -> {
213             CountDownLatch testCompleteComputationStarted = new CountDownLatch(1);
214             CountDownLatch testCompleteComputationContinue = new CountDownLatch(1);
215             ConsoleIOContextTestSupport.IMPL = new ConsoleIOContextTestSupport() {
216                 @Override
217                 protected void willComputeCompletionCallback() {
218                     if (testCompleteComputationStarted != null) {
219                         testCompleteComputationStarted.countDown();
220                     }
221                     if (testCompleteComputationContinue != null) {
222                         try {
223                             testCompleteComputationContinue.await();
224                         } catch (InterruptedException ex) {
225                             throw new IllegalStateException(ex);
226                         }
227                     }
228                 }
229             };
230             //-> <tab>
231             inputSink.write(TAB);
232             testCompleteComputationStarted.await();
233             //-> <tab><tab>
234             inputSink.write(TAB + TAB);
235             testCompleteComputationContinue.countDown();
236             waitOutput(out, PROMPT);
237             //-> <tab>
238             inputSink.write(TAB);
239             waitOutput(out, PROMPT);
240             ConsoleIOContextTestSupport.IMPL = null;
241         });
242     }
243 
testNoRepeat()244     public void testNoRepeat() throws Exception {
245         doRunTest((inputSink, out) -> {
246             inputSink.write("String xyzAA;\n");
247             waitOutput(out, PROMPT);
248 
249             //xyz<tab>
250             inputSink.write("String s = xyz" + TAB);
251             waitOutput(out, "^String s = xyzAA");
252             inputSink.write(".");
253             waitOutput(out, "^\\.");
254 
255             inputSink.write(INTERRUPT);
256             waitOutput(out, PROMPT);
257 
258             inputSink.write("double xyzAB;\n");
259             waitOutput(out, PROMPT);
260 
261             //xyz<tab>
262             inputSink.write("String s = xyz" + TAB);
263             String allCompletions =
264                     resource("jshell.console.completion.all.completions");
265             waitOutput(out, ".*xyzAA.*" + allCompletions + ".*\u0005String s = xyzA");
266         });
267     }
268 
testCrash8221759()269     public void testCrash8221759() throws Exception {
270         doRunTest((inputSink, out) -> {
271             inputSink.write("java.io.File.path" + TAB);
272             waitOutput(out, "java.io.File.path\n" +
273                             "pathSeparator       pathSeparatorChar   " +
274                             REDRAW_PROMPT + "java.io.File.pathSeparator");
275         });
276     }
277 
prepareZip()278     private Path prepareZip() {
279         String clazz1 =
280                 "package jshelltest;\n" +
281                 "/**JShellTest 0" +
282                 " */\n" +
283                 "public class JShellTest {\n" +
284                 "    /**JShellTest 1\n" +
285                 "     * <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1\n" +
286                 "     * <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1\n" +
287                 "     * <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1 <p>1\n" +
288                 "     */\n" +
289                 "    public JShellTest(String str) {}\n" +
290                 "    /**JShellTest 2" +
291                 "     */\n" +
292                 "    public JShellTest(String str, int i) {}\n" +
293                 "}\n";
294 
295         String clazz2 =
296                 "package jshelltest;\n" +
297                 "/**JShellTestAux 0" +
298                 " */\n" +
299                 "public class JShellTestAux {\n" +
300                 "    /**JShellTest 1" +
301                 "     */\n" +
302                 "    public JShellTestAux(String str) { }\n" +
303                 "    /**JShellTest 2" +
304                 "     */\n" +
305                 "    public JShellTestAux(String str, int i) { }\n" +
306                 "}\n";
307 
308         Path srcZip = Paths.get("src.zip");
309 
310         try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(srcZip))) {
311             out.putNextEntry(new JarEntry("jshelltest/JShellTest.java"));
312             out.write(clazz1.getBytes());
313             out.putNextEntry(new JarEntry("jshelltest/JShellTestAux.java"));
314             out.write(clazz2.getBytes());
315         } catch (IOException ex) {
316             throw new IllegalStateException(ex);
317         }
318 
319         compiler.compile(clazz1, clazz2);
320 
321         try {
322             Field availableSources = Class.forName("jdk.jshell.SourceCodeAnalysisImpl").getDeclaredField("availableSourcesOverride");
323             availableSources.setAccessible(true);
324             availableSources.set(null, Arrays.asList(srcZip));
325         } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException | ClassNotFoundException ex) {
326             throw new IllegalStateException(ex);
327         }
328 
329         return compiler.getClassDir();
330     }
331     //where:
332         private final Compiler compiler = new Compiler();
333 
334 }
335