ToolSimpleTest.java revision 3968:fc0a9318d392
1/*
2 * Copyright (c) 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 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073 8173848 8174041 8173916 8174028
27 * @summary Simple jshell tool tests
28 * @modules jdk.compiler/com.sun.tools.javac.api
29 *          jdk.compiler/com.sun.tools.javac.main
30 *          jdk.jdeps/com.sun.tools.javap
31 *          jdk.jshell/jdk.internal.jshell.tool
32 * @build KullaTesting TestingInputStream
33 * @run testng ToolSimpleTest
34 */
35import java.util.Arrays;
36import java.util.ArrayList;
37import java.util.List;
38import java.util.Locale;
39import java.util.function.Consumer;
40import java.util.stream.Collectors;
41import java.util.stream.Stream;
42
43import org.testng.annotations.Test;
44
45import static org.testng.Assert.assertEquals;
46import static org.testng.Assert.assertTrue;
47
48public class ToolSimpleTest extends ReplToolTesting {
49
50    @Test
51    public void testRemaining() {
52        test(
53                (a) -> assertCommand(a, "int z; z =", "z ==> 0"),
54                (a) -> assertCommand(a, "5", "z ==> 5"),
55                (a) -> assertCommand(a, "/*nada*/; int q =", ""),
56                (a) -> assertCommand(a, "77", "q ==> 77"),
57                (a) -> assertCommand(a, "//comment;", ""),
58                (a) -> assertCommand(a, "int v;", "v ==> 0"),
59                (a) -> assertCommand(a, "int v; int c",
60                        "v ==> 0\n" +
61                        "c ==> 0")
62        );
63    }
64
65    @Test
66    public void testOpenComment() {
67        test(
68                (a) -> assertCommand(a, "int z = /* blah", ""),
69                (a) -> assertCommand(a, "baz */ 5", "z ==> 5"),
70                (a) -> assertCommand(a, "/** hoge ", ""),
71                (a) -> assertCommand(a, "baz **/", ""),
72                (a) -> assertCommand(a, "int v", "v ==> 0")
73        );
74    }
75
76    @Test
77    public void testLessThan() {
78        test(
79                (a) -> assertCommand(a, "45", "$1 ==> 45"),
80                (a) -> assertCommand(a, "72", "$2 ==> 72"),
81                (a) -> assertCommand(a, "$1 < $2", "$3 ==> true"),
82                (a) -> assertCommand(a, "int a, b", "a ==> 0\n" +
83                        "b ==> 0"),
84                (a) -> assertCommand(a, "a < b", "$6 ==> false")
85        );
86    }
87
88    @Test
89    public void oneLineOfError() {
90        test(
91                (a) -> assertCommand(a, "12+", null),
92                (a) -> assertCommandCheckOutput(a, "  true", (s) ->
93                        assertTrue(s.contains("12+") && !s.contains("true"), "Output: '" + s + "'"))
94        );
95    }
96
97    @Test
98    public void defineVariables() {
99        test(
100                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
101                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
102                (a) -> assertVariable(a, "int", "a"),
103                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
104                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
105                (a) -> assertVariable(a, "double", "a", "1", "1.0"),
106                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
107                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
108                (a) -> evaluateExpression(a, "double", "2 * a", "2.0"),
109                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
110                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables())
111        );
112    }
113
114    @Test
115    public void defineMethods() {
116        test(
117                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
118                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
119                (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
120                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
121                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
122                (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"),
123                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
124                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
125                (a) -> assertMethod(a, "void g() {}", "()void", "g"),
126                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
127                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods())
128        );
129    }
130
131    @Test
132    public void defineTypes() {
133        test(
134                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
135                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
136                (a) -> assertClass(a, "class A { }", "class", "A"),
137                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
138                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
139                (a) -> assertClass(a, "interface A { }", "interface", "A"),
140                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
141                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
142                (a) -> assertClass(a, "enum A { }", "enum", "A"),
143                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
144                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
145                (a) -> assertClass(a, "@interface A { }", "@interface", "A"),
146                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
147                (a) -> assertCommandCheckOutput(a, "/types", assertClasses())
148        );
149    }
150
151    @Test
152    public void defineImports() {
153        test(
154                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
155                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
156                (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"),
157                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
158                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
159                (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
160                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
161                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
162                (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"),
163                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
164                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
165                (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"),
166                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
167                (a) -> assertCommandCheckOutput(a, "/imports", assertImports())
168        );
169    }
170
171    @Test
172    public void defineVar() {
173        test(
174                (a) -> assertCommand(a, "int x = 72", "x ==> 72"),
175                (a) -> assertCommand(a, "x", "x ==> 72"),
176                (a) -> assertCommand(a, "/vars", "|    int x = 72")
177        );
178    }
179
180    @Test
181    public void defineUnresolvedVar() {
182        test(
183                (a) -> assertCommand(a, "undefined x",
184                        "|  created variable x, however, it cannot be referenced until class undefined is declared"),
185                (a) -> assertCommand(a, "/vars", "|    undefined x = (not-active)")
186        );
187    }
188
189    @Test
190    public void testUnresolved() {
191        test(
192                (a) -> assertCommand(a, "int f() { return g() + x + new A().a; }",
193                        "|  created method f(), however, it cannot be invoked until method g(), variable x, and class A are declared"),
194                (a) -> assertCommand(a, "f()",
195                        "|  attempted to call method f() which cannot be invoked until method g(), variable x, and class A are declared"),
196                (a) -> assertCommandOutputStartsWith(a, "int g() { return x; }",
197                        "|  created method g(), however, it cannot be invoked until variable x is declared"),
198                (a) -> assertCommand(a, "g()", "|  attempted to call method g() which cannot be invoked until variable x is declared")
199        );
200    }
201
202    @Test
203    public void testUnknownCommand() {
204        test((a) -> assertCommand(a, "/unknown",
205                "|  No such command or snippet id: /unknown\n" +
206                "|  Type /help for help."));
207    }
208
209    @Test
210    public void testEmptyClassPath() {
211        test(after -> assertCommand(after, "/env --class-path", "|  Argument to class-path missing."));
212    }
213
214    @Test
215    public void testNoArgument() {
216        test(
217                (a) -> assertCommand(a, "/save",
218                        "|  '/save' requires a filename argument."),
219                (a) -> assertCommand(a, "/open",
220                        "|  '/open' requires a filename argument."),
221                (a) -> assertCommandOutputStartsWith(a, "/drop",
222                        "|  In the /drop argument, please specify an import, variable, method, or class to drop.")
223        );
224    }
225
226    @Test
227    public void testDebug() {
228        test(
229                (a) -> assertCommand(a, "/deb", "|  Debugging on"),
230                (a) -> assertCommand(a, "/debug", "|  Debugging off"),
231                (a) -> assertCommand(a, "/debug", "|  Debugging on"),
232                (a) -> assertCommand(a, "/deb", "|  Debugging off")
233        );
234    }
235
236    @Test
237    public void testDrop() {
238        test(false, new String[]{"--no-startup"},
239                a -> assertVariable(a, "int", "a"),
240                a -> dropVariable(a, "/drop 1", "int a = 0", "|  dropped variable a"),
241                a -> assertMethod(a, "int b() { return 0; }", "()int", "b"),
242                a -> dropMethod(a, "/drop 2", "int b()", "|  dropped method b()"),
243                a -> assertClass(a, "class A {}", "class", "A"),
244                a -> dropClass(a, "/drop 3", "class A", "|  dropped class A"),
245                a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
246                a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""),
247                a -> assertCommand(a, "for (int i = 0; i < 10; ++i) {}", ""),
248                a -> assertCommand(a, "/drop 5", ""),
249                a -> assertCommand(a, "/list", ""),
250                a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
251                a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
252                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
253                a -> assertCommandCheckOutput(a, "/imports", assertImports())
254        );
255        test(false, new String[]{"--no-startup"},
256                a -> assertVariable(a, "int", "a"),
257                a -> dropVariable(a, "/drop a", "int a = 0", "|  dropped variable a"),
258                a -> assertMethod(a, "int b() { return 0; }", "()int", "b"),
259                a -> dropMethod(a, "/drop b", "int b()", "|  dropped method b()"),
260                a -> assertClass(a, "class A {}", "class", "A"),
261                a -> dropClass(a, "/drop A", "class A", "|  dropped class A"),
262                a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
263                a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
264                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
265                a -> assertCommandCheckOutput(a, "/imports", assertImports())
266        );
267    }
268
269    @Test
270    public void testDropNegative() {
271        test(false, new String[]{"--no-startup"},
272                a -> assertCommandOutputStartsWith(a, "/drop 0", "|  No such snippet: 0"),
273                a -> assertCommandOutputStartsWith(a, "/drop a", "|  No such snippet: a"),
274                a -> assertCommandCheckOutput(a, "/drop",
275                        assertStartsWith("|  In the /drop argument, please specify an import, variable, method, or class to drop.")),
276                a -> assertVariable(a, "int", "a"),
277                a -> assertCommand(a, "a", "a ==> 0"),
278                a -> assertCommand(a, "/drop 2", ""),
279                a -> assertCommand(a, "/drop 2",
280                        "|  This command does not accept the snippet '2' : a\n" +
281                        "|  See /types, /methods, /vars, or /list")
282        );
283    }
284
285    @Test
286    public void testAmbiguousDrop() {
287        Consumer<String> check = s -> {
288            assertTrue(s.startsWith("|  The argument references more than one import, variable, method, or class"), s);
289            int lines = s.split("\n").length;
290            assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s);
291        };
292        test(
293                a -> assertVariable(a, "int", "a"),
294                a -> assertMethod(a, "int a() { return 0; }", "()int", "a"),
295                a -> assertClass(a, "class a {}", "class", "a"),
296                a -> assertCommandCheckOutput(a, "/drop a", check),
297                a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
298                a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
299                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
300                a -> assertCommandCheckOutput(a, "/imports", assertImports())
301        );
302        test(
303                a -> assertMethod(a, "int a() { return 0; }", "()int", "a"),
304                a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"),
305                a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"),
306                a -> assertCommandCheckOutput(a, "/drop a", check),
307                a -> assertCommandCheckOutput(a, "/methods", assertMethods())
308        );
309    }
310
311    @Test
312    public void testApplicationOfPost() {
313        test(
314                (a) -> assertCommand(a, "/set mode t normal -command", "|  Created new feedback mode: t"),
315                (a) -> assertCommand(a, "/set feedback t", "|  Feedback mode: t"),
316                (a) -> assertCommand(a, "/set format t post \"$%n\"", ""),
317                (a) -> assertCommand(a, "/set prompt t \"+\" \"-\"", ""),
318                (a) -> assertCommand(a, "/set prompt t", "|  /set prompt t \"+\" \"-\"$")
319        );
320    }
321
322    @Test
323    public void testHelpLength() {
324        Consumer<String> testOutput = (s) -> {
325            List<String> ss = Stream.of(s.split("\n"))
326                    .filter(l -> !l.isEmpty())
327                    .collect(Collectors.toList());
328            assertTrue(ss.size() >= 10, "Help does not print enough lines:" + s);
329        };
330        test(
331                (a) -> assertCommandCheckOutput(a, "/?", testOutput),
332                (a) -> assertCommandCheckOutput(a, "/help", testOutput),
333                (a) -> assertCommandCheckOutput(a, "/help /list", testOutput)
334        );
335    }
336
337    @Test
338    public void testHelp() {
339        test(
340                (a) -> assertHelp(a, "/?", "/list", "/help", "/exit", "intro"),
341                (a) -> assertHelp(a, "/help", "/list", "/help", "/exit", "intro"),
342                (a) -> assertHelp(a, "/help short", "shortcuts", "<tab>"),
343                (a) -> assertHelp(a, "/? /li", "/list -all", "snippets"),
344                (a) -> assertHelp(a, "/help /set prompt", "optionally contain '%s'", "quoted"),
345                (a) -> assertHelp(a, "/help /help", "/help <command>")
346        );
347    }
348
349    @Test
350    public void testHelpFormat() {
351        test(
352                (a) -> assertCommandCheckOutput(a, "/help", s -> {
353                    String[] lines = s.split("\\R");
354                    assertTrue(lines.length > 20,
355                            "Too few lines of /help output: " + lines.length
356                          + "\n" + s);
357                    for (int i = 0; i < lines.length; ++i) {
358                        String l = lines[i];
359                        assertTrue(l.startsWith("| "),
360                                "Expected /help line to start with | :\n" + l);
361                        assertTrue(l.length() <= 80,
362                                "/help line too long: " + l.length() + "\n" + l);
363                    }
364                 })
365        );
366    }
367
368    private void assertHelp(boolean a, String command, String... find) {
369        assertCommandCheckOutput(a, command, s -> {
370            for (String f : find) {
371                assertTrue(s.contains(f),
372                        "Expected output of " + command + " to contain: " + f
373                      + "\n" + s);
374            }
375        });
376    }
377
378    // Check that each line of output contains the corresponding string from the list
379    private void checkLineToList(String in, List<String> match) {
380        String trimmed = in.trim();
381        String[] res = trimmed.isEmpty()
382                ? new String[0]
383                : trimmed.split("\n");
384        assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res));
385        for (int i = 0; i < match.size(); ++i) {
386            assertTrue(res[i].contains(match.get(i)));
387        }
388    }
389
390    @Test
391    public void testListArgs() {
392        String arg = "qqqq";
393        List<String> startVarList = new ArrayList<>(START_UP);
394        startVarList.add("int aardvark");
395        test(
396                a -> assertCommandCheckOutput(a, "/list -all",
397                        s -> checkLineToList(s, START_UP)),
398                a -> assertCommandOutputStartsWith(a, "/list " + arg,
399                        "|  No such snippet: " + arg),
400                a -> assertVariable(a, "int", "aardvark"),
401                a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"),
402                a -> assertCommandCheckOutput(a, "/list -start",
403                        s -> checkLineToList(s, START_UP)),
404                a -> assertCommandCheckOutput(a, "/list -all",
405                        s -> checkLineToList(s, startVarList)),
406                a -> assertCommandOutputStartsWith(a, "/list s3",
407                        "s3 : import"),
408                a -> assertCommandOutputStartsWith(a, "/list " + arg,
409                        "|  No such snippet: " + arg)
410        );
411    }
412
413    @Test
414    public void testVarsArgs() {
415        String arg = "qqqq";
416        List<String> startVarList = new ArrayList<>();
417        test(
418                a -> assertCommandCheckOutput(a, "/vars -all",
419                        s -> checkLineToList(s, startVarList)),
420                a -> assertCommand(a, "/vars " + arg,
421                        "|  No such snippet: " + arg),
422                a -> assertVariable(a, "int", "aardvark"),
423                a -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
424                a -> assertVariable(a, "int", "a"),
425                a -> assertVariable(a, "double", "a", "1", "1.0"),
426                a -> assertCommandOutputStartsWith(a, "/vars aardvark",
427                        "|    int aardvark = 0"),
428                a -> assertCommandCheckOutput(a, "/vars -start",
429                        s -> checkLineToList(s, startVarList)),
430                a -> assertCommandOutputStartsWith(a, "/vars -all",
431                        "|    int aardvark = 0\n|    int a = "),
432                a -> assertCommandOutputStartsWith(a, "/vars f",
433                        "|  This command does not accept the snippet 'f'"),
434                a -> assertCommand(a, "/var " + arg,
435                        "|  No such snippet: " + arg)
436        );
437    }
438
439    @Test
440    public void testMethodsArgs() {
441        String arg = "qqqq";
442        List<String> printingMethodList = new ArrayList<>(PRINTING_CMD_METHOD);
443        test(new String[]{"--startup", "PRINTING"},
444                a -> assertCommandCheckOutput(a, "/methods -all",
445                        s -> checkLineToList(s, printingMethodList)),
446                a -> assertCommandCheckOutput(a, "/methods -start",
447                        s -> checkLineToList(s, printingMethodList)),
448                a -> assertCommandCheckOutput(a, "/methods print println printf",
449                        s -> checkLineToList(s, printingMethodList)),
450                a -> assertCommandCheckOutput(a, "/methods println",
451                        s -> assertEquals(s.trim().split("\n").length, 10)),
452                a -> assertCommandCheckOutput(a, "/methods",
453                        s -> checkLineToList(s, printingMethodList)),
454                a -> assertCommandOutputStartsWith(a, "/methods " + arg,
455                        "|  No such snippet: " + arg),
456                a -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
457                a -> assertVariable(a, "int", "aardvark"),
458                a -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"),
459                a -> assertMethod(a, "void g() {}", "()void", "g"),
460                a -> assertCommandOutputStartsWith(a, "/methods " + arg,
461                        "|  No such snippet: " + arg),
462                a -> assertCommandOutputStartsWith(a, "/methods aardvark",
463                        "|  This command does not accept the snippet 'aardvark' : int aardvark"),
464                a -> assertCommandCheckOutput(a, "/methods -start",
465                        s -> checkLineToList(s, printingMethodList)),
466                a -> assertCommandCheckOutput(a, "/methods print println printf",
467                        s -> checkLineToList(s, printingMethodList)),
468                a -> assertCommandOutputStartsWith(a, "/methods g",
469                        "|    void g()"),
470                a -> assertCommandOutputStartsWith(a, "/methods f",
471                        "|    int f()\n" +
472                        "|    void f(int)")
473        );
474    }
475
476    @Test
477    public void testMethodsWithErrors() {
478        test(new String[]{"--no-startup"},
479                a -> assertCommand(a, "double m(int x) { return x; }",
480                        "|  created method m(int)"),
481                a -> assertCommand(a, "GARBAGE junk() { return TRASH; }",
482                        "|  created method junk(), however, it cannot be referenced until class GARBAGE, and variable TRASH are declared"),
483                a -> assertCommand(a, "int w = 5;",
484                        "w ==> 5"),
485                a -> assertCommand(a, "int tyer() { return w; }",
486                        "|  created method tyer()"),
487                a -> assertCommand(a, "String w = \"hi\";",
488                        "w ==> \"hi\""),
489                a -> assertCommand(a, "/methods",
490                        "|    double m(int)\n" +
491                        "|    GARBAGE junk()\n" +
492                        "|       which cannot be referenced until class GARBAGE, and variable TRASH are declared\n" +
493                        "|    int tyer()\n" +
494                        "|       which cannot be invoked until this error is corrected: \n" +
495                        "|          incompatible types: java.lang.String cannot be converted to int\n" +
496                        "|          int tyer() { return w; }\n" +
497                        "|                              ^\n")
498        );
499    }
500
501    @Test
502    public void testTypesWithErrors() {
503        test(new String[]{"--no-startup"},
504                a -> assertCommand(a, "class C extends NONE { int x; }",
505                        "|  created class C, however, it cannot be referenced until class NONE is declared"),
506                a -> assertCommand(a, "class D { void m() { System.out.println(nada); } }",
507                        "|  created class D, however, it cannot be instanciated or its methods invoked until variable nada is declared"),
508                a -> assertCommand(a, "/types",
509                        "|    class C\n" +
510                        "|       which cannot be referenced until class NONE is declared\n" +
511                        "|    class D\n" +
512                        "|       which cannot be instanciated or its methods invoked until variable nada is declared\n")
513        );
514    }
515
516    @Test
517    public void testTypesArgs() {
518        String arg = "qqqq";
519        List<String> startTypeList = new ArrayList<>();
520        test(
521                a -> assertCommandCheckOutput(a, "/types -all",
522                        s -> checkLineToList(s, startTypeList)),
523                a -> assertCommandCheckOutput(a, "/types -start",
524                        s -> checkLineToList(s, startTypeList)),
525                a -> assertCommandOutputStartsWith(a, "/types " + arg,
526                        "|  No such snippet: " + arg),
527                a -> assertVariable(a, "int", "aardvark"),
528                (a) -> assertClass(a, "class A { }", "class", "A"),
529                (a) -> assertClass(a, "interface A { }", "interface", "A"),
530                a -> assertCommandOutputStartsWith(a, "/types -all",
531                        "|    class A\n" +
532                        "|    interface A"),
533                (a) -> assertClass(a, "enum E { }", "enum", "E"),
534                (a) -> assertClass(a, "@interface B { }", "@interface", "B"),
535                a -> assertCommand(a, "/types aardvark",
536                        "|  This command does not accept the snippet 'aardvark' : int aardvark;"),
537                a -> assertCommandOutputStartsWith(a, "/types A",
538                        "|    interface A"),
539                a -> assertCommandOutputStartsWith(a, "/types E",
540                        "|    enum E"),
541                a -> assertCommandOutputStartsWith(a, "/types B",
542                        "|    @interface B"),
543                a -> assertCommandOutputStartsWith(a, "/types " + arg,
544                        "|  No such snippet: " + arg),
545                a -> assertCommandCheckOutput(a, "/types -start",
546                        s -> checkLineToList(s, startTypeList))
547        );
548    }
549
550    @Test
551    public void testBlankLinesInSnippetContinuation() {
552        test(Locale.ROOT, false, new String[]{"--no-startup"}, "",
553                a -> assertCommand(a, "class C {",
554                        ""),
555                a -> assertCommand(a, "",
556                        ""),
557                a -> assertCommand(a, "",
558                        ""),
559                a -> assertCommand(a, "  int x;",
560                        ""),
561                a -> assertCommand(a, "",
562                        ""),
563                a -> assertCommand(a, "",
564                        ""),
565                a -> assertCommand(a, "}",
566                        "|  created class C"),
567                a -> assertCommand(a, "/list",
568                        "\n" +
569                        "   1 : class C {\n" +
570                        "       \n" +
571                        "       \n" +
572                        "         int x;\n" +
573                        "       \n" +
574                        "       \n" +
575                        "       }")
576        );
577    }
578
579    @Test
580    public void testCompoundStart() {
581        test(new String[]{"--startup", "DEFAULT", "--startup", "PRINTING"},
582                (a) -> assertCommand(a, "printf(\"%4.2f\", Math.PI)",
583                        "", "", null, "3.14", "")
584        );
585    }
586
587    @Test
588    public void testJavaSeStart() {
589        test(new String[]{"--startup", "JAVASE"},
590                (a) -> assertCommand(a, "ZoneOffsetTransitionRule.TimeDefinition.WALL",
591                        "$1 ==> WALL")
592        );
593    }
594
595    @Test
596    public void defineClasses() {
597        test(
598                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
599                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
600                (a) -> assertClass(a, "class A { }", "class", "A"),
601                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
602                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
603                (a) -> assertClass(a, "interface A { }", "interface", "A"),
604                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
605                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
606                (a) -> assertClass(a, "enum A { }", "enum", "A"),
607                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
608                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
609                (a) -> assertClass(a, "@interface A { }", "@interface", "A"),
610                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
611                (a) -> assertCommandCheckOutput(a, "/types", assertClasses())
612        );
613    }
614
615    @Test
616    public void testCommandPrefix() {
617        test(a -> assertCommandCheckOutput(a, "/s",
618                      assertStartsWith("|  Command: '/s' is ambiguous: /save, /set")),
619             a -> assertCommand(a, "int var", "var ==> 0"),
620             a -> assertCommandCheckOutput(a, "/va",
621                      assertStartsWith("|    int var = 0")),
622             a -> assertCommandCheckOutput(a, "/save",
623                      assertStartsWith("|  '/save' requires a filename argument.")));
624    }
625
626    @Test
627    public void testOptionQ() {
628        test(Locale.ROOT, false, new String[]{"-q", "--no-startup"}, "",
629                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
630                (a) -> assertCommand(a, "int x = 5", "")
631        );
632    }
633
634    @Test
635    public void testOptionS() {
636        test(Locale.ROOT, false, new String[]{"-s", "--no-startup"}, "",
637                (a) -> assertCommand(a, "1+1", "")
638        );
639    }
640
641    @Test
642    public void testOptionV() {
643        test(new String[]{"-v", "--no-startup"},
644                (a) -> assertCommand(a, "1+1",
645                        "$1 ==> 2\n" +
646                        "|  created scratch variable $1 : int")
647        );
648    }
649
650    @Test
651    public void testOptionFeedback() {
652        test(Locale.ROOT, false, new String[]{"--feedback", "concise", "--no-startup"}, "",
653                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
654                (a) -> assertCommand(a, "int x = 5", "")
655        );
656    }
657
658    @Test
659    public void testCompoundOptions() {
660        Consumer<String> confirmNoStartup = s -> {
661                    assertEquals(0, Stream.of(s.split("\n"))
662                            .filter(l -> !l.isEmpty())
663                            .count(), "Expected no lines: " + s);
664                };
665        test(Locale.ROOT, false, new String[]{"-nq"}, "",
666                (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup),
667                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
668                (a) -> assertCommand(a, "int x = 5", "")
669        );
670        test(Locale.ROOT, false, new String[]{"-qn"}, "",
671                (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup),
672                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
673                (a) -> assertCommand(a, "int x = 5", "")
674        );
675        test(Locale.ROOT, false, new String[]{"-ns"}, "",
676                (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup),
677                (a) -> assertCommand(a, "1+1", "")
678        );
679    }
680
681    @Test
682    public void testOptionR() {
683        test(new String[]{"-R-Dthe.sound=blorp", "--no-startup"},
684                (a) -> assertCommand(a, "System.getProperty(\"the.sound\")",
685                        "$1 ==> \"blorp\"")
686        );
687    }
688
689    @Test
690    public void testWrapSourceHandlerDiagCrash() {
691        test(new String[]{"--add-exports", "jdk.javadoc/ALL-UNNAMED"},
692                (a) -> assertCommand(a, "1+1", "$1 ==> 2")
693         );
694    }
695
696    @Test
697    public void test8156910() {
698        test(
699                (a) -> assertCommandOutputContains(a, "System.out.println(\"%5d\", 10);", "%5d"),
700                (a) -> assertCommandOutputContains(a, "1234", "==> 1234")
701        );
702    }
703}
704