ToolSimpleTest.java revision 3849:b2e915d476be
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
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 oneLineOfError() {
78        test(
79                (a) -> assertCommand(a, "12+", null),
80                (a) -> assertCommandCheckOutput(a, "  true", (s) ->
81                        assertTrue(s.contains("12+") && !s.contains("true"), "Output: '" + s + "'"))
82        );
83    }
84
85    @Test
86    public void defineVariables() {
87        test(
88                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
89                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
90                (a) -> assertVariable(a, "int", "a"),
91                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
92                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
93                (a) -> assertVariable(a, "double", "a", "1", "1.0"),
94                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
95                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()),
96                (a) -> evaluateExpression(a, "double", "2 * a", "2.0"),
97                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
98                (a) -> assertCommandCheckOutput(a, "/vars", assertVariables())
99        );
100    }
101
102    @Test
103    public void defineMethods() {
104        test(
105                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
106                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
107                (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
108                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
109                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
110                (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"),
111                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
112                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()),
113                (a) -> assertMethod(a, "void g() {}", "()void", "g"),
114                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
115                (a) -> assertCommandCheckOutput(a, "/methods", assertMethods())
116        );
117    }
118
119    @Test
120    public void defineTypes() {
121        test(
122                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
123                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
124                (a) -> assertClass(a, "class A { }", "class", "A"),
125                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
126                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
127                (a) -> assertClass(a, "interface A { }", "interface", "A"),
128                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
129                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
130                (a) -> assertClass(a, "enum A { }", "enum", "A"),
131                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
132                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
133                (a) -> assertClass(a, "@interface A { }", "@interface", "A"),
134                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
135                (a) -> assertCommandCheckOutput(a, "/types", assertClasses())
136        );
137    }
138
139    @Test
140    public void defineImports() {
141        test(
142                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
143                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
144                (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"),
145                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
146                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
147                (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
148                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
149                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
150                (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"),
151                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
152                (a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
153                (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"),
154                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
155                (a) -> assertCommandCheckOutput(a, "/imports", assertImports())
156        );
157    }
158
159    @Test
160    public void defineVar() {
161        test(
162                (a) -> assertCommand(a, "int x = 72", "x ==> 72"),
163                (a) -> assertCommand(a, "x", "x ==> 72"),
164                (a) -> assertCommand(a, "/vars", "|    int x = 72")
165        );
166    }
167
168    @Test
169    public void defineUnresolvedVar() {
170        test(
171                (a) -> assertCommand(a, "undefined x",
172                        "|  created variable x, however, it cannot be referenced until class undefined is declared"),
173                (a) -> assertCommand(a, "/vars", "|    undefined x = (not-active)")
174        );
175    }
176
177    @Test
178    public void testUnresolved() {
179        test(
180                (a) -> assertCommand(a, "int f() { return g() + x + new A().a; }",
181                        "|  created method f(), however, it cannot be invoked until method g(), variable x, and class A are declared"),
182                (a) -> assertCommand(a, "f()",
183                        "|  attempted to call method f() which cannot be invoked until method g(), variable x, and class A are declared"),
184                (a) -> assertCommandOutputStartsWith(a, "int g() { return x; }",
185                        "|  created method g(), however, it cannot be invoked until variable x is declared"),
186                (a) -> assertCommand(a, "g()", "|  attempted to call method g() which cannot be invoked until variable x is declared")
187        );
188    }
189
190    @Test
191    public void testUnknownCommand() {
192        test((a) -> assertCommand(a, "/unknown",
193                "|  No such command or snippet id: /unknown\n" +
194                "|  Type /help for help."));
195    }
196
197    @Test
198    public void testEmptyClassPath() {
199        test(after -> assertCommand(after, "/classpath", "|  The /classpath command requires a path argument."));
200    }
201
202    @Test
203    public void testNoArgument() {
204        test(
205                (a) -> assertCommand(a, "/save",
206                        "|  '/save' requires a filename argument."),
207                (a) -> assertCommand(a, "/open",
208                        "|  '/open' requires a filename argument."),
209                (a) -> assertCommandOutputStartsWith(a, "/drop",
210                        "|  In the /drop argument, please specify an import, variable, method, or class to drop.")
211        );
212    }
213
214    @Test
215    public void testDebug() {
216        test(
217                (a) -> assertCommand(a, "/deb", "|  Debugging on"),
218                (a) -> assertCommand(a, "/debug", "|  Debugging off"),
219                (a) -> assertCommand(a, "/debug", "|  Debugging on"),
220                (a) -> assertCommand(a, "/deb", "|  Debugging off")
221        );
222    }
223
224    @Test
225    public void testDrop() {
226        test(false, new String[]{"--no-startup"},
227                a -> assertVariable(a, "int", "a"),
228                a -> dropVariable(a, "/drop 1", "int a = 0", "|  dropped variable a"),
229                a -> assertMethod(a, "int b() { return 0; }", "()I", "b"),
230                a -> dropMethod(a, "/drop 2", "b ()I", "|  dropped method b()"),
231                a -> assertClass(a, "class A {}", "class", "A"),
232                a -> dropClass(a, "/drop 3", "class A", "|  dropped class A"),
233                a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
234                a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""),
235                a -> assertCommand(a, "for (int i = 0; i < 10; ++i) {}", ""),
236                a -> assertCommand(a, "/drop 5", ""),
237                a -> assertCommand(a, "/list", ""),
238                a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
239                a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
240                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
241                a -> assertCommandCheckOutput(a, "/imports", assertImports())
242        );
243        test(false, new String[]{"--no-startup"},
244                a -> assertVariable(a, "int", "a"),
245                a -> dropVariable(a, "/drop a", "int a = 0", "|  dropped variable a"),
246                a -> assertMethod(a, "int b() { return 0; }", "()I", "b"),
247                a -> dropMethod(a, "/drop b", "b ()I", "|  dropped method b()"),
248                a -> assertClass(a, "class A {}", "class", "A"),
249                a -> dropClass(a, "/drop A", "class A", "|  dropped class A"),
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    }
256
257    @Test
258    public void testDropNegative() {
259        test(false, new String[]{"--no-startup"},
260                a -> assertCommandOutputStartsWith(a, "/drop 0", "|  No such snippet: 0"),
261                a -> assertCommandOutputStartsWith(a, "/drop a", "|  No such snippet: a"),
262                a -> assertCommandCheckOutput(a, "/drop",
263                        assertStartsWith("|  In the /drop argument, please specify an import, variable, method, or class to drop.")),
264                a -> assertVariable(a, "int", "a"),
265                a -> assertCommand(a, "a", "a ==> 0"),
266                a -> assertCommand(a, "/drop 2", ""),
267                a -> assertCommand(a, "/drop 2",
268                        "|  This command does not accept the snippet '2' : a\n" +
269                        "|  See /types, /methods, /vars, or /list")
270        );
271    }
272
273    @Test
274    public void testAmbiguousDrop() {
275        Consumer<String> check = s -> {
276            assertTrue(s.startsWith("|  The argument references more than one import, variable, method, or class"), s);
277            int lines = s.split("\n").length;
278            assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s);
279        };
280        test(
281                a -> assertVariable(a, "int", "a"),
282                a -> assertMethod(a, "int a() { return 0; }", "()int", "a"),
283                a -> assertClass(a, "class a {}", "class", "a"),
284                a -> assertCommandCheckOutput(a, "/drop a", check),
285                a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
286                a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
287                a -> assertCommandCheckOutput(a, "/types", assertClasses()),
288                a -> assertCommandCheckOutput(a, "/imports", assertImports())
289        );
290        test(
291                a -> assertMethod(a, "int a() { return 0; }", "()int", "a"),
292                a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"),
293                a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"),
294                a -> assertCommandCheckOutput(a, "/drop a", check),
295                a -> assertCommandCheckOutput(a, "/methods", assertMethods())
296        );
297    }
298
299    @Test
300    public void testApplicationOfPost() {
301        test(
302                (a) -> assertCommand(a, "/set mode t normal -command", "|  Created new feedback mode: t"),
303                (a) -> assertCommand(a, "/set feedback t", "|  Feedback mode: t"),
304                (a) -> assertCommand(a, "/set format t post \"$%n\"", ""),
305                (a) -> assertCommand(a, "/set prompt t \"+\" \"-\"", ""),
306                (a) -> assertCommand(a, "/set prompt t", "|  /set prompt t \"+\" \"-\"$")
307        );
308    }
309
310    @Test
311    public void testHelpLength() {
312        Consumer<String> testOutput = (s) -> {
313            List<String> ss = Stream.of(s.split("\n"))
314                    .filter(l -> !l.isEmpty())
315                    .collect(Collectors.toList());
316            assertTrue(ss.size() >= 10, "Help does not print enough lines:" + s);
317        };
318        test(
319                (a) -> assertCommandCheckOutput(a, "/?", testOutput),
320                (a) -> assertCommandCheckOutput(a, "/help", testOutput),
321                (a) -> assertCommandCheckOutput(a, "/help /list", testOutput)
322        );
323    }
324
325    @Test
326    public void testHelp() {
327        test(
328                (a) -> assertHelp(a, "/?", "/list", "/help", "/exit", "intro"),
329                (a) -> assertHelp(a, "/help", "/list", "/help", "/exit", "intro"),
330                (a) -> assertHelp(a, "/help short", "shortcuts", "<tab>"),
331                (a) -> assertHelp(a, "/? /li", "/list -all", "snippets"),
332                (a) -> assertHelp(a, "/help /set prompt", "optionally contain '%s'", "quoted"),
333                (a) -> assertHelp(a, "/help /help", "/help <command>")
334        );
335    }
336
337    @Test
338    public void testHelpFormat() {
339        test(
340                (a) -> assertCommandCheckOutput(a, "/help", s -> {
341                    String[] lines = s.split("\\R");
342                    assertTrue(lines.length > 20,
343                            "Too few lines of /help output: " + lines.length
344                          + "\n" + s);
345                    for (int i = 0; i < lines.length; ++i) {
346                        String l = lines[i];
347                        assertTrue(l.startsWith("| "),
348                                "Expected /help line to start with | :\n" + l);
349                        assertTrue(l.length() <= 80,
350                                "/help line too long: " + l.length() + "\n" + l);
351                    }
352                 })
353        );
354    }
355
356    private void assertHelp(boolean a, String command, String... find) {
357        assertCommandCheckOutput(a, command, s -> {
358            for (String f : find) {
359                assertTrue(s.contains(f),
360                        "Expected output of " + command + " to contain: " + f
361                      + "\n" + s);
362            }
363        });
364    }
365
366    // Check that each line of output contains the corresponding string from the list
367    private void checkLineToList(String in, List<String> match) {
368        String trimmed = in.trim();
369        String[] res = trimmed.isEmpty()
370                ? new String[0]
371                : trimmed.split("\n");
372        assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res));
373        for (int i = 0; i < match.size(); ++i) {
374            assertTrue(res[i].contains(match.get(i)));
375        }
376    }
377
378    @Test
379    public void testListArgs() {
380        String arg = "qqqq";
381        List<String> startVarList = new ArrayList<>(START_UP);
382        startVarList.add("int aardvark");
383        test(
384                a -> assertCommandCheckOutput(a, "/list -all",
385                        s -> checkLineToList(s, START_UP)),
386                a -> assertCommandOutputStartsWith(a, "/list " + arg,
387                        "|  No such snippet: " + arg),
388                a -> assertVariable(a, "int", "aardvark"),
389                a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"),
390                a -> assertCommandCheckOutput(a, "/list -start",
391                        s -> checkLineToList(s, START_UP)),
392                a -> assertCommandCheckOutput(a, "/list -all",
393                        s -> checkLineToList(s, startVarList)),
394                a -> assertCommandOutputStartsWith(a, "/list s3",
395                        "s3 : import"),
396                a -> assertCommandOutputStartsWith(a, "/list " + arg,
397                        "|  No such snippet: " + arg)
398        );
399    }
400
401    @Test
402    public void testVarsArgs() {
403        String arg = "qqqq";
404        List<String> startVarList = new ArrayList<>();
405        test(
406                a -> assertCommandCheckOutput(a, "/vars -all",
407                        s -> checkLineToList(s, startVarList)),
408                a -> assertCommand(a, "/vars " + arg,
409                        "|  No such snippet: " + arg),
410                a -> assertVariable(a, "int", "aardvark"),
411                a -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
412                a -> assertVariable(a, "int", "a"),
413                a -> assertVariable(a, "double", "a", "1", "1.0"),
414                a -> assertCommandOutputStartsWith(a, "/vars aardvark",
415                        "|    int aardvark = 0"),
416                a -> assertCommandCheckOutput(a, "/vars -start",
417                        s -> checkLineToList(s, startVarList)),
418                a -> assertCommandOutputStartsWith(a, "/vars -all",
419                        "|    int aardvark = 0\n|    int a = "),
420                a -> assertCommandOutputStartsWith(a, "/vars f",
421                        "|  This command does not accept the snippet 'f'"),
422                a -> assertCommand(a, "/var " + arg,
423                        "|  No such snippet: " + arg)
424        );
425    }
426
427    @Test
428    public void testMethodsArgs() {
429        String arg = "qqqq";
430        List<String> printingMethodList = new ArrayList<>(PRINTING_CMD_METHOD);
431        test(new String[]{"--startup", "PRINTING"},
432                a -> assertCommandCheckOutput(a, "/methods -all",
433                        s -> checkLineToList(s, printingMethodList)),
434                a -> assertCommandCheckOutput(a, "/methods -start",
435                        s -> checkLineToList(s, printingMethodList)),
436                a -> assertCommandCheckOutput(a, "/methods print println printf",
437                        s -> checkLineToList(s, printingMethodList)),
438                a -> assertCommandCheckOutput(a, "/methods println",
439                        s -> assertEquals(s.trim().split("\n").length, 10)),
440                a -> assertCommandCheckOutput(a, "/methods",
441                        s -> checkLineToList(s, printingMethodList)),
442                a -> assertCommandOutputStartsWith(a, "/methods " + arg,
443                        "|  No such snippet: " + arg),
444                a -> assertMethod(a, "int f() { return 0; }", "()int", "f"),
445                a -> assertVariable(a, "int", "aardvark"),
446                a -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"),
447                a -> assertMethod(a, "void g() {}", "()void", "g"),
448                a -> assertCommandOutputStartsWith(a, "/methods " + arg,
449                        "|  No such snippet: " + arg),
450                a -> assertCommandOutputStartsWith(a, "/methods aardvark",
451                        "|  This command does not accept the snippet 'aardvark' : int aardvark"),
452                a -> assertCommandCheckOutput(a, "/methods -start",
453                        s -> checkLineToList(s, printingMethodList)),
454                a -> assertCommandCheckOutput(a, "/methods print println printf",
455                        s -> checkLineToList(s, printingMethodList)),
456                a -> assertCommandOutputStartsWith(a, "/methods g",
457                        "|    g ()void"),
458                a -> assertCommandOutputStartsWith(a, "/methods f",
459                        "|    f ()int\n" +
460                        "|    f (int)void")
461        );
462    }
463
464    @Test
465    public void testTypesArgs() {
466        String arg = "qqqq";
467        List<String> startTypeList = new ArrayList<>();
468        test(
469                a -> assertCommandCheckOutput(a, "/types -all",
470                        s -> checkLineToList(s, startTypeList)),
471                a -> assertCommandCheckOutput(a, "/types -start",
472                        s -> checkLineToList(s, startTypeList)),
473                a -> assertCommandOutputStartsWith(a, "/types " + arg,
474                        "|  No such snippet: " + arg),
475                a -> assertVariable(a, "int", "aardvark"),
476                (a) -> assertClass(a, "class A { }", "class", "A"),
477                (a) -> assertClass(a, "interface A { }", "interface", "A"),
478                a -> assertCommandOutputStartsWith(a, "/types -all",
479                        "|    class A\n" +
480                        "|    interface A"),
481                (a) -> assertClass(a, "enum E { }", "enum", "E"),
482                (a) -> assertClass(a, "@interface B { }", "@interface", "B"),
483                a -> assertCommand(a, "/types aardvark",
484                        "|  This command does not accept the snippet 'aardvark' : int aardvark;"),
485                a -> assertCommandOutputStartsWith(a, "/types A",
486                        "|    interface A"),
487                a -> assertCommandOutputStartsWith(a, "/types E",
488                        "|    enum E"),
489                a -> assertCommandOutputStartsWith(a, "/types B",
490                        "|    @interface B"),
491                a -> assertCommandOutputStartsWith(a, "/types " + arg,
492                        "|  No such snippet: " + arg),
493                a -> assertCommandCheckOutput(a, "/types -start",
494                        s -> checkLineToList(s, startTypeList))
495        );
496    }
497
498    @Test
499    public void testCompoundStart() {
500        test(new String[]{"--startup", "DEFAULT", "--startup", "PRINTING"},
501                (a) -> assertCommand(a, "printf(\"%4.2f\", Math.PI)",
502                        "", "", null, "3.14", "")
503        );
504    }
505
506    @Test
507    public void testJavaSeStart() {
508        test(new String[]{"--startup", "JAVASE"},
509                (a) -> assertCommand(a, "ZoneOffsetTransitionRule.TimeDefinition.WALL",
510                        "$1 ==> WALL")
511        );
512    }
513
514    @Test
515    public void defineClasses() {
516        test(
517                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
518                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
519                (a) -> assertClass(a, "class A { }", "class", "A"),
520                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
521                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
522                (a) -> assertClass(a, "interface A { }", "interface", "A"),
523                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
524                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
525                (a) -> assertClass(a, "enum A { }", "enum", "A"),
526                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
527                (a) -> assertCommandCheckOutput(a, "/types", assertClasses()),
528                (a) -> assertClass(a, "@interface A { }", "@interface", "A"),
529                (a) -> assertCommandCheckOutput(a, "/list", assertList()),
530                (a) -> assertCommandCheckOutput(a, "/types", assertClasses())
531        );
532    }
533
534    @Test
535    public void testCommandPrefix() {
536        test(a -> assertCommandCheckOutput(a, "/s",
537                      assertStartsWith("|  Command: '/s' is ambiguous: /save, /set")),
538             a -> assertCommand(a, "int var", "var ==> 0"),
539             a -> assertCommandCheckOutput(a, "/va",
540                      assertStartsWith("|    int var = 0")),
541             a -> assertCommandCheckOutput(a, "/save",
542                      assertStartsWith("|  '/save' requires a filename argument.")));
543    }
544
545    @Test
546    public void testOptionQ() {
547        test(Locale.ROOT, false, new String[]{"-q", "--no-startup"}, "",
548                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
549                (a) -> assertCommand(a, "int x = 5", "")
550        );
551    }
552
553    @Test
554    public void testOptionS() {
555        test(Locale.ROOT, false, new String[]{"-s", "--no-startup"}, "",
556                (a) -> assertCommand(a, "1+1", "")
557        );
558    }
559
560    @Test
561    public void testOptionV() {
562        test(new String[]{"-v", "--no-startup"},
563                (a) -> assertCommand(a, "1+1",
564                        "$1 ==> 2\n" +
565                        "|  created scratch variable $1 : int")
566        );
567    }
568
569    @Test
570    public void testOptionFeedback() {
571        test(Locale.ROOT, false, new String[]{"--feedback", "concise", "--no-startup"}, "",
572                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
573                (a) -> assertCommand(a, "int x = 5", "")
574        );
575    }
576
577    @Test
578    public void testCompoundOptions() {
579        Consumer<String> confirmNoStartup = s -> {
580                    assertEquals(0, Stream.of(s.split("\n"))
581                            .filter(l -> !l.isEmpty())
582                            .count(), "Expected no lines: " + s);
583                };
584        test(Locale.ROOT, false, new String[]{"-nq"}, "",
585                (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup),
586                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
587                (a) -> assertCommand(a, "int x = 5", "")
588        );
589        test(Locale.ROOT, false, new String[]{"-qn"}, "",
590                (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup),
591                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
592                (a) -> assertCommand(a, "int x = 5", "")
593        );
594        test(Locale.ROOT, false, new String[]{"-ns"}, "",
595                (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup),
596                (a) -> assertCommand(a, "1+1", "")
597        );
598    }
599
600    @Test
601    public void testOptionR() {
602        test(new String[]{"-R-Dthe.sound=blorp", "--no-startup"},
603                (a) -> assertCommand(a, "System.getProperty(\"the.sound\")",
604                        "$1 ==> \"blorp\"")
605        );
606    }
607
608    @Test
609    public void test8156910() {
610        test(
611                (a) -> assertCommandOutputContains(a, "System.out.println(\"%5d\", 10);", "%5d"),
612                (a) -> assertCommandOutputContains(a, "1234", "==> 1234")
613        );
614    }
615}
616