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