blob: a2be490511c31874293867a5418224a8e36c1c0d [file] [log] [blame]
Jan Lahodaa21102b2015-10-19 19:15:16 +02001/*
Robert Field51ea0802016-03-08 11:53:35 -08002 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
Jan Lahodaa21102b2015-10-19 19:15:16 +02003 * 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
24import java.io.ByteArrayOutputStream;
25import java.io.OutputStream;
26import java.io.PrintStream;
27import java.util.ArrayList;
28import java.util.Arrays;
Robert Field0caaad62015-12-10 23:27:06 -080029import java.util.Collections;
Jan Lahodaa21102b2015-10-19 19:15:16 +020030import java.util.HashMap;
Jan Lahodaa21102b2015-10-19 19:15:16 +020031import java.util.List;
Robert Fielda80f8502016-04-04 10:31:20 -070032import java.util.Locale;
Jan Lahodaa21102b2015-10-19 19:15:16 +020033import java.util.Map;
Jan Lahodaa21102b2015-10-19 19:15:16 +020034import java.util.function.Consumer;
Shinya Yoshidafadea542015-11-12 08:48:42 +010035import java.util.function.Function;
Jan Lahodaa21102b2015-10-19 19:15:16 +020036import java.util.function.Predicate;
Jan Lahodaa981a562016-03-23 13:40:42 +010037import java.util.prefs.AbstractPreferences;
38import java.util.prefs.BackingStoreException;
39import java.util.prefs.Preferences;
Jan Lahodaa21102b2015-10-19 19:15:16 +020040import java.util.regex.Matcher;
41import java.util.regex.Pattern;
42import java.util.stream.Collectors;
43import java.util.stream.Stream;
44
45import jdk.internal.jshell.tool.JShellTool;
46import jdk.jshell.SourceCodeAnalysis.Suggestion;
47
Jan Lahodaa981a562016-03-23 13:40:42 +010048import org.testng.annotations.BeforeMethod;
49
Robert Field0caaad62015-12-10 23:27:06 -080050import static java.util.stream.Collectors.toList;
Jan Lahodaa21102b2015-10-19 19:15:16 +020051import static org.testng.Assert.assertEquals;
52import static org.testng.Assert.assertNotNull;
53import static org.testng.Assert.assertTrue;
54import static org.testng.Assert.fail;
55
56public class ReplToolTesting {
57
58 private final static String DEFAULT_STARTUP_MESSAGE = "| Welcome to";
Robert Field0caaad62015-12-10 23:27:06 -080059 final static List<ImportInfo> START_UP_IMPORTS = Stream.of(
60 "java.util.*",
61 "java.io.*",
62 "java.math.*",
63 "java.net.*",
64 "java.util.concurrent.*",
65 "java.util.prefs.*",
66 "java.util.regex.*")
67 .map(s -> new ImportInfo("import " + s + ";", "", s))
68 .collect(toList());
69 final static List<MethodInfo> START_UP_METHODS = Stream.of(
70 new MethodInfo("void printf(String format, Object... args) { System.out.printf(format, args); }",
71 "(String,Object...)void", "printf"))
72 .collect(toList());
73 final static List<String> START_UP = Collections.unmodifiableList(
74 Stream.concat(START_UP_IMPORTS.stream(), START_UP_METHODS.stream())
75 .map(s -> s.getSource())
76 .collect(toList()));
Jan Lahodaa21102b2015-10-19 19:15:16 +020077
78 private WaitingTestingInputStream cmdin = null;
79 private ByteArrayOutputStream cmdout = null;
80 private ByteArrayOutputStream cmderr = null;
81 private PromptedCommandOutputStream console = null;
82 private TestingInputStream userin = null;
83 private ByteArrayOutputStream userout = null;
84 private ByteArrayOutputStream usererr = null;
85
86 private List<MemberInfo> keys;
87 private Map<String, VariableInfo> variables;
88 private Map<String, MethodInfo> methods;
89 private Map<String, ClassInfo> classes;
Shinya Yoshidafadea542015-11-12 08:48:42 +010090 private Map<String, ImportInfo> imports;
Jan Lahodaa21102b2015-10-19 19:15:16 +020091 private boolean isDefaultStartUp = true;
Jan Lahodaa981a562016-03-23 13:40:42 +010092 private Preferences prefs;
Jan Lahodaa21102b2015-10-19 19:15:16 +020093
94 public JShellTool repl = null;
95
96 public interface ReplTest {
97 void run(boolean after);
98 }
99
100 public void setCommandInput(String s) {
101 cmdin.setInput(s);
102 }
103
104 public final static Pattern idPattern = Pattern.compile("^\\s+(\\d+)");
105 public Consumer<String> assertList() {
106 return s -> {
107 List<String> lines = Stream.of(s.split("\n"))
108 .filter(l -> !l.isEmpty())
109 .collect(Collectors.toList());
110 int previousId = Integer.MIN_VALUE;
111 assertEquals(lines.size(), keys.size(), "Number of keys");
112 for (int i = 0; i < lines.size(); ++i) {
113 String line = lines.get(i);
114 Matcher matcher = idPattern.matcher(line);
115 assertTrue(matcher.find(), "Snippet id not found: " + line);
116 String src = keys.get(i).getSource();
117 assertTrue(line.endsWith(src), "Line '" + line + "' does not end with: " + src);
118 int id = Integer.parseInt(matcher.group(1));
119 assertTrue(previousId < id,
120 String.format("The previous id is not less than the next one: previous: %d, next: %d",
121 previousId, id));
122 previousId = id;
123 }
124 };
125 }
126
127 private final static Pattern extractPattern = Pattern.compile("^\\| *(.*)$");
128 private Consumer<String> assertMembers(String message, Map<String, ? extends MemberInfo> set) {
129 return s -> {
130 List<String> lines = Stream.of(s.split("\n"))
131 .filter(l -> !l.isEmpty())
132 .collect(Collectors.toList());
133 assertEquals(lines.size(), set.size(), message + " : expected: " + set.keySet() + "\ngot:\n" + lines);
134 for (String line : lines) {
135 Matcher matcher = extractPattern.matcher(line);
136 assertTrue(matcher.find(), line);
137 String src = matcher.group(1);
138 MemberInfo info = set.get(src);
139 assertNotNull(info, "Not found snippet with signature: " + src + ", line: "
140 + line + ", keys: " + set.keySet() + "\n");
141 }
142 };
143 }
144
145 public Consumer<String> assertVariables() {
146 return assertMembers("Variables", variables);
147 }
148
149 public Consumer<String> assertMethods() {
150 return assertMembers("Methods", methods);
151 }
152
153 public Consumer<String> assertClasses() {
154 return assertMembers("Classes", classes);
155 }
156
Shinya Yoshidafadea542015-11-12 08:48:42 +0100157 public Consumer<String> assertImports() {
158 return assertMembers("Imports", imports);
159 }
160
Jan Lahodaa21102b2015-10-19 19:15:16 +0200161 public String getCommandOutput() {
Jan Lahoda1ee440e2016-01-13 14:24:34 +0100162 String s = normalizeLineEndings(cmdout.toString());
Jan Lahodaa21102b2015-10-19 19:15:16 +0200163 cmdout.reset();
164 return s;
165 }
166
167 public String getCommandErrorOutput() {
Jan Lahoda1ee440e2016-01-13 14:24:34 +0100168 String s = normalizeLineEndings(cmderr.toString());
Jan Lahodaa21102b2015-10-19 19:15:16 +0200169 cmderr.reset();
170 return s;
171 }
172
173 public void setUserInput(String s) {
174 userin.setInput(s);
175 }
176
177 public String getUserOutput() {
Jan Lahoda1ee440e2016-01-13 14:24:34 +0100178 String s = normalizeLineEndings(userout.toString());
Jan Lahodaa21102b2015-10-19 19:15:16 +0200179 userout.reset();
180 return s;
181 }
182
183 public String getUserErrorOutput() {
Jan Lahoda1ee440e2016-01-13 14:24:34 +0100184 String s = normalizeLineEndings(usererr.toString());
Jan Lahodaa21102b2015-10-19 19:15:16 +0200185 usererr.reset();
186 return s;
187 }
188
189 public void test(ReplTest... tests) {
190 test(new String[0], tests);
191 }
192
193 public void test(String[] args, ReplTest... tests) {
194 test(true, args, tests);
195 }
196
197 public void test(boolean isDefaultStartUp, String[] args, ReplTest... tests) {
Robert Fielda80f8502016-04-04 10:31:20 -0700198 test(Locale.ROOT, isDefaultStartUp, args, DEFAULT_STARTUP_MESSAGE, tests);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200199 }
200
Robert Fielda80f8502016-04-04 10:31:20 -0700201 public void test(Locale locale, boolean isDefaultStartUp, String[] args, String startUpMessage, ReplTest... tests) {
Jan Lahodaa21102b2015-10-19 19:15:16 +0200202 this.isDefaultStartUp = isDefaultStartUp;
203 initSnippets();
204 ReplTest[] wtests = new ReplTest[tests.length + 3];
205 wtests[0] = a -> assertCommandCheckOutput(a, "<start>",
206 s -> assertTrue(s.startsWith(startUpMessage), "Expected start-up message '" + startUpMessage + "' Got: " + s));
207 wtests[1] = a -> assertCommand(a, "/debug 0", null);
208 System.arraycopy(tests, 0, wtests, 2, tests.length);
209 wtests[tests.length + 2] = a -> assertCommand(a, "/exit", null);
Robert Fielda80f8502016-04-04 10:31:20 -0700210 testRaw(locale, args, wtests);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200211 }
212
213 private void initSnippets() {
214 keys = new ArrayList<>();
215 variables = new HashMap<>();
216 methods = new HashMap<>();
217 classes = new HashMap<>();
Shinya Yoshidafadea542015-11-12 08:48:42 +0100218 imports = new HashMap<>();
Jan Lahodaa21102b2015-10-19 19:15:16 +0200219 if (isDefaultStartUp) {
Robert Field0caaad62015-12-10 23:27:06 -0800220 methods.putAll(
221 START_UP_METHODS.stream()
222 .collect(Collectors.toMap(Object::toString, Function.identity())));
Shinya Yoshidafadea542015-11-12 08:48:42 +0100223 imports.putAll(
Robert Field0caaad62015-12-10 23:27:06 -0800224 START_UP_IMPORTS.stream()
Shinya Yoshidafadea542015-11-12 08:48:42 +0100225 .collect(Collectors.toMap(Object::toString, Function.identity())));
Jan Lahodaa21102b2015-10-19 19:15:16 +0200226 }
227 }
228
Jan Lahodaa981a562016-03-23 13:40:42 +0100229 @BeforeMethod
230 public void setUp() {
231 prefs = new MemoryPreferences();
232 }
233
Robert Fielda80f8502016-04-04 10:31:20 -0700234 public void testRaw(Locale locale, String[] args, ReplTest... tests) {
Jan Lahodaa21102b2015-10-19 19:15:16 +0200235 cmdin = new WaitingTestingInputStream();
236 cmdout = new ByteArrayOutputStream();
237 cmderr = new ByteArrayOutputStream();
238 console = new PromptedCommandOutputStream(tests);
239 userin = new TestingInputStream();
240 userout = new ByteArrayOutputStream();
241 usererr = new ByteArrayOutputStream();
242 repl = new JShellTool(
243 cmdin,
244 new PrintStream(cmdout),
245 new PrintStream(cmderr),
246 new PrintStream(console),
247 userin,
248 new PrintStream(userout),
Jan Lahodaa981a562016-03-23 13:40:42 +0100249 new PrintStream(usererr),
Robert Fielda80f8502016-04-04 10:31:20 -0700250 prefs,
251 locale);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200252 repl.testPrompt = true;
253 try {
254 repl.start(args);
255 } catch (Exception ex) {
256 fail("Repl tool died with exception", ex);
257 }
258 // perform internal consistency checks on state, if desired
259 String cos = getCommandOutput();
260 String ceos = getCommandErrorOutput();
261 String uos = getUserOutput();
262 String ueos = getUserErrorOutput();
Robert Fielda80f8502016-04-04 10:31:20 -0700263 assertTrue((cos.isEmpty() || cos.startsWith("| Goodbye") || !locale.equals(Locale.ROOT)),
Jan Lahodaa21102b2015-10-19 19:15:16 +0200264 "Expected a goodbye, but got: " + cos);
265 assertTrue(ceos.isEmpty(), "Expected empty error output, got: " + ceos);
266 assertTrue(uos.isEmpty(), "Expected empty output, got: " + uos);
267 assertTrue(ueos.isEmpty(), "Expected empty error output, got: " + ueos);
268 }
269
270 public void assertReset(boolean after, String cmd) {
271 assertCommand(after, cmd, "| Resetting state.\n");
272 initSnippets();
273 }
274
275 public void evaluateExpression(boolean after, String type, String expr, String value) {
Robert Field1889a6c2016-04-12 22:23:11 -0700276 String output = String.format("(\\$\\d+) ==> %s", value);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200277 Pattern outputPattern = Pattern.compile(output);
278 assertCommandCheckOutput(after, expr, s -> {
279 Matcher matcher = outputPattern.matcher(s);
280 assertTrue(matcher.find(), "Output: '" + s + "' does not fit pattern: '" + output + "'");
281 String name = matcher.group(1);
282 VariableInfo tempVar = new TempVariableInfo(expr, type, name, value);
283 variables.put(tempVar.toString(), tempVar);
284 addKey(after, tempVar);
285 });
286 }
287
288 public void loadVariable(boolean after, String type, String name) {
289 loadVariable(after, type, name, null, null);
290 }
291
292 public void loadVariable(boolean after, String type, String name, String expr, String value) {
293 String src = expr == null
294 ? String.format("%s %s", type, name)
295 : String.format("%s %s = %s", type, name, expr);
296 VariableInfo var = expr == null
297 ? new VariableInfo(src, type, name)
298 : new VariableInfo(src, type, name, value);
299 addKey(after, var, variables);
300 addKey(after, var);
301 }
302
303 public void assertVariable(boolean after, String type, String name) {
304 assertVariable(after, type, name, null, null);
305 }
306
307 public void assertVariable(boolean after, String type, String name, String expr, String value) {
308 String src = expr == null
309 ? String.format("%s %s", type, name)
310 : String.format("%s %s = %s", type, name, expr);
311 VariableInfo var = expr == null
312 ? new VariableInfo(src, type, name)
313 : new VariableInfo(src, type, name, value);
314 assertCommandCheckOutput(after, src, var.checkOutput());
315 addKey(after, var, variables);
316 addKey(after, var);
317 }
318
319 public void loadMethod(boolean after, String src, String signature, String name) {
320 MethodInfo method = new MethodInfo(src, signature, name);
321 addKey(after, method, methods);
322 addKey(after, method);
323 }
324
325 public void assertMethod(boolean after, String src, String signature, String name) {
326 MethodInfo method = new MethodInfo(src, signature, name);
327 assertCommandCheckOutput(after, src, method.checkOutput());
328 addKey(after, method, methods);
329 addKey(after, method);
330 }
331
332 public void loadClass(boolean after, String src, String type, String name) {
333 ClassInfo clazz = new ClassInfo(src, type, name);
334 addKey(after, clazz, classes);
335 addKey(after, clazz);
336 }
337
338 public void assertClass(boolean after, String src, String type, String name) {
339 ClassInfo clazz = new ClassInfo(src, type, name);
340 assertCommandCheckOutput(after, src, clazz.checkOutput());
341 addKey(after, clazz, classes);
342 addKey(after, clazz);
343 }
344
Shinya Yoshidafadea542015-11-12 08:48:42 +0100345 public void loadImport(boolean after, String src, String type, String name) {
346 ImportInfo i = new ImportInfo(src, type, name);
347 addKey(after, i, imports);
348 addKey(after, i);
349 }
350
351 public void assertImport(boolean after, String src, String type, String name) {
352 ImportInfo i = new ImportInfo(src, type, name);
353 assertCommandCheckOutput(after, src, i.checkOutput());
354 addKey(after, i, imports);
355 addKey(after, i);
356 }
357
Jan Lahodaa21102b2015-10-19 19:15:16 +0200358 private <T extends MemberInfo> void addKey(boolean after, T memberInfo, Map<String, T> map) {
359 if (after) {
360 map.entrySet().removeIf(e -> e.getValue().equals(memberInfo));
361 map.put(memberInfo.toString(), memberInfo);
362 }
363 }
364
365 private <T extends MemberInfo> void addKey(boolean after, T memberInfo) {
366 if (after) {
367 for (int i = 0; i < keys.size(); ++i) {
368 MemberInfo m = keys.get(i);
369 if (m.equals(memberInfo)) {
370 keys.set(i, memberInfo);
371 return;
372 }
373 }
374 keys.add(memberInfo);
375 }
376 }
377
Robert Fielde16d3742016-03-25 18:36:19 -0700378 private void dropKey(boolean after, String cmd, String name, Map<String, ? extends MemberInfo> map, String output) {
379 assertCommand(after, cmd, output);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200380 if (after) {
381 map.remove(name);
382 for (int i = 0; i < keys.size(); ++i) {
383 MemberInfo m = keys.get(i);
384 if (m.toString().equals(name)) {
385 keys.remove(i);
386 return;
387 }
388 }
389 throw new AssertionError("Key not found: " + name + ", keys: " + keys);
390 }
391 }
392
Robert Fielde16d3742016-03-25 18:36:19 -0700393 public void dropVariable(boolean after, String cmd, String name, String output) {
394 dropKey(after, cmd, name, variables, output);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200395 }
396
Robert Fielde16d3742016-03-25 18:36:19 -0700397 public void dropMethod(boolean after, String cmd, String name, String output) {
398 dropKey(after, cmd, name, methods, output);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200399 }
400
Robert Fielde16d3742016-03-25 18:36:19 -0700401 public void dropClass(boolean after, String cmd, String name, String output) {
402 dropKey(after, cmd, name, classes, output);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200403 }
404
Robert Fielde16d3742016-03-25 18:36:19 -0700405 public void dropImport(boolean after, String cmd, String name, String output) {
406 dropKey(after, cmd, name, imports, output);
Shinya Yoshidafadea542015-11-12 08:48:42 +0100407 }
408
Jan Lahodaa21102b2015-10-19 19:15:16 +0200409 public void assertCommand(boolean after, String cmd, String out) {
410 assertCommand(after, cmd, out, "", null, "", "");
411 }
412
Robert Field51ea0802016-03-08 11:53:35 -0800413 public void assertCommandOutputContains(boolean after, String cmd, String has) {
414 assertCommandCheckOutput(after, cmd, (s) ->
415 assertTrue(s.contains(has), "Output: \'" + s + "' does not contain: " + has));
416 }
417
418 public void assertCommandOutputStartsWith(boolean after, String cmd, String starts) {
419 assertCommandCheckOutput(after, cmd, assertStartsWith(starts));
420 }
421
Jan Lahodaa21102b2015-10-19 19:15:16 +0200422 public void assertCommandCheckOutput(boolean after, String cmd, Consumer<String> check) {
423 if (!after) {
424 assertCommand(false, cmd, null);
425 } else {
426 String got = getCommandOutput();
427 check.accept(got);
428 assertCommand(true, cmd, null);
429 }
430 }
431
432 public void assertCommand(boolean after, String cmd, String out, String err,
433 String userinput, String print, String usererr) {
434 if (!after) {
435 if (userinput != null) {
436 setUserInput(userinput);
437 }
438 setCommandInput(cmd + "\n");
439 } else {
Yuji Kubotab9873212016-04-09 11:03:48 -0700440 assertOutput(getCommandOutput().trim(), out==null? out : out.trim(), "command output: " + cmd);
Robert Fielde16d3742016-03-25 18:36:19 -0700441 assertOutput(getCommandErrorOutput(), err, "command error: " + cmd);
442 assertOutput(getUserOutput(), print, "user output: " + cmd);
443 assertOutput(getUserErrorOutput(), usererr, "user error: " + cmd);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200444 }
445 }
446
447 public void assertCompletion(boolean after, String code, boolean isSmart, String... expected) {
448 if (!after) {
449 setCommandInput("\n");
450 } else {
451 assertCompletion(code, isSmart, expected);
452 }
453 }
454
455 public void assertCompletion(String code, boolean isSmart, String... expected) {
456 List<String> completions = computeCompletions(code, isSmart);
457 assertEquals(completions, Arrays.asList(expected), "Command: " + code + ", output: " +
458 completions.toString());
459 }
460
461 private List<String> computeCompletions(String code, boolean isSmart) {
Robert Field51ea0802016-03-08 11:53:35 -0800462 JShellTool js = this.repl != null ? this.repl
Robert Fielda80f8502016-04-04 10:31:20 -0700463 : new JShellTool(null, null, null, null, null, null, null, prefs, Locale.ROOT);
Jan Lahodaa21102b2015-10-19 19:15:16 +0200464 int cursor = code.indexOf('|');
465 code = code.replace("|", "");
466 assertTrue(cursor > -1, "'|' not found: " + code);
467 List<Suggestion> completions =
Robert Field51ea0802016-03-08 11:53:35 -0800468 js.commandCompletionSuggestions(code, cursor, new int[1]); //XXX: ignoring anchor for now
Jan Lahodaa21102b2015-10-19 19:15:16 +0200469 return completions.stream()
470 .filter(s -> isSmart == s.isSmart)
471 .map(s -> s.continuation)
472 .distinct()
473 .collect(Collectors.toList());
474 }
475
476 public Consumer<String> assertStartsWith(String prefix) {
477 return (output) -> assertTrue(output.startsWith(prefix), "Output: \'" + output + "' does not start with: " + prefix);
478 }
479
Robert Fielde16d3742016-03-25 18:36:19 -0700480 public void assertOutput(String got, String expected, String display) {
Jan Lahodaa21102b2015-10-19 19:15:16 +0200481 if (expected != null) {
Robert Fielde16d3742016-03-25 18:36:19 -0700482 assertEquals(got, expected, display + ".\n");
Jan Lahodaa21102b2015-10-19 19:15:16 +0200483 }
484 }
485
Jan Lahoda1ee440e2016-01-13 14:24:34 +0100486 private String normalizeLineEndings(String text) {
487 return text.replace(System.getProperty("line.separator"), "\n");
488 }
489
Jan Lahodaa21102b2015-10-19 19:15:16 +0200490 public static abstract class MemberInfo {
491 public final String source;
492 public final String type;
493 public final String name;
494
495 public MemberInfo(String source, String type, String name) {
496 this.source = source;
497 this.type = type;
498 this.name = name;
499 }
500
501 @Override
502 public int hashCode() {
503 return name.hashCode();
504 }
505
Robert Field51ea0802016-03-08 11:53:35 -0800506 @Override
507 public boolean equals(Object o) {
508 if (o instanceof MemberInfo) {
509 MemberInfo mi = (MemberInfo) o;
510 return name.equals(mi.name);
511 }
512 return false;
513 }
514
Jan Lahodaa21102b2015-10-19 19:15:16 +0200515 public abstract Consumer<String> checkOutput();
516
517 public String getSource() {
518 return source;
519 }
520 }
521
522 public static class VariableInfo extends MemberInfo {
523
524 public final String value;
525 public final String initialValue;
526
527 public VariableInfo(String src, String type, String name) {
528 super(src, type, name);
529 this.initialValue = null;
530 switch (type) {
531 case "byte":
532 case "short":
533 case "int":
534 case "long":
535 value = "0";
536 break;
537 case "boolean":
538 value = "false";
539 break;
540 case "char":
541 value = "''";
542 break;
543 case "float":
544 case "double":
545 value = "0.0";
546 break;
547 default:
548 value = "null";
549 }
550 }
551
552 public VariableInfo(String src, String type, String name, String value) {
553 super(src, type, name);
554 this.value = value;
555 this.initialValue = value;
556 }
557
558 @Override
559 public Consumer<String> checkOutput() {
Robert Field1889a6c2016-04-12 22:23:11 -0700560 String arrowPattern = String.format("%s ==> %s", name, value);
561 Predicate<String> arrowCheckOutput = Pattern.compile(arrowPattern).asPredicate();
562 String howeverPattern = String.format("\\| *\\w+ variable %s, however*.", name);
563 Predicate<String> howeverCheckOutput = Pattern.compile(howeverPattern).asPredicate();
564 return output -> {
565 if (output.startsWith("| ")) {
566 assertTrue(howeverCheckOutput.test(output),
567 "Output: " + output + " does not fit pattern: " + howeverPattern);
568 } else {
569 assertTrue(arrowCheckOutput.test(output),
570 "Output: " + output + " does not fit pattern: " + arrowPattern);
571 }
572 };
Jan Lahodaa21102b2015-10-19 19:15:16 +0200573 }
574
575 @Override
Robert Field51ea0802016-03-08 11:53:35 -0800576 public int hashCode() {
577 return name.hashCode();
578 }
579
580 @Override
Jan Lahodaa21102b2015-10-19 19:15:16 +0200581 public boolean equals(Object o) {
582 if (o instanceof VariableInfo) {
583 VariableInfo v = (VariableInfo) o;
584 return name.equals(v.name);
585 }
586 return false;
587 }
588
589 @Override
590 public String toString() {
591 return String.format("%s %s = %s", type, name, value);
592 }
593
594 @Override
595 public String getSource() {
596 String src = super.getSource();
597 return src.endsWith(";") ? src : src + ";";
598 }
599 }
600
601 public static class TempVariableInfo extends VariableInfo {
602
603 public TempVariableInfo(String src, String type, String name, String value) {
604 super(src, type, name, value);
605 }
606
607 @Override
608 public String getSource() {
609 return source;
610 }
611 }
612
613 public static class MethodInfo extends MemberInfo {
614
615 public final String signature;
616
617 public MethodInfo(String source, String signature, String name) {
618 super(source, signature.substring(0, signature.lastIndexOf(')') + 1), name);
619 this.signature = signature;
620 }
621
622 @Override
623 public Consumer<String> checkOutput() {
624 String expectedOutput = String.format("\\| *\\w+ method %s", name);
625 Predicate<String> checkOutput = Pattern.compile(expectedOutput).asPredicate();
626 return s -> assertTrue(checkOutput.test(s), "Expected: '" + expectedOutput + "', actual: " + s);
627 }
628
Robert Field51ea0802016-03-08 11:53:35 -0800629 @Override
630 public int hashCode() {
631 return (name.hashCode() << 2) ^ type.hashCode() ;
632 }
Jan Lahodaa21102b2015-10-19 19:15:16 +0200633
634 @Override
635 public boolean equals(Object o) {
636 if (o instanceof MemberInfo) {
637 MemberInfo m = (MemberInfo) o;
638 return name.equals(m.name) && type.equals(m.type);
639 }
640 return false;
641 }
642
643 @Override
644 public String toString() {
645 return String.format("%s %s", name, signature);
646 }
647 }
648
649 public static class ClassInfo extends MemberInfo {
650
651 public ClassInfo(String source, String type, String name) {
652 super(source, type, name);
653 }
654
655 @Override
656 public Consumer<String> checkOutput() {
657 String fullType = type.equals("@interface")? "annotation interface" : type;
658 String expectedOutput = String.format("\\| *\\w+ %s %s", fullType, name);
659 Predicate<String> checkOutput = Pattern.compile(expectedOutput).asPredicate();
660 return s -> assertTrue(checkOutput.test(s), "Expected: '" + expectedOutput + "', actual: " + s);
661 }
662
663 @Override
Robert Field51ea0802016-03-08 11:53:35 -0800664 public int hashCode() {
665 return name.hashCode() ;
666 }
667
668 @Override
Jan Lahodaa21102b2015-10-19 19:15:16 +0200669 public boolean equals(Object o) {
670 if (o instanceof ClassInfo) {
671 ClassInfo c = (ClassInfo) o;
672 return name.equals(c.name);
673 }
674 return false;
675 }
676
677 @Override
678 public String toString() {
679 return String.format("%s %s", type, name);
680 }
681 }
682
Shinya Yoshidafadea542015-11-12 08:48:42 +0100683 public static class ImportInfo extends MemberInfo {
684 public ImportInfo(String source, String type, String fullname) {
685 super(source, type, fullname);
686 }
687
688 @Override
689 public Consumer<String> checkOutput() {
690 return s -> assertTrue("".equals(s), "Expected: '', actual: " + s);
691 }
692
693 @Override
Robert Field51ea0802016-03-08 11:53:35 -0800694 public int hashCode() {
695 return (name.hashCode() << 2) ^ type.hashCode() ;
696 }
697
698 @Override
Shinya Yoshidafadea542015-11-12 08:48:42 +0100699 public boolean equals(Object o) {
700 if (o instanceof ImportInfo) {
701 ImportInfo i = (ImportInfo) o;
702 return name.equals(i.name) && type.equals(i.type);
703 }
704 return false;
705 }
706
707 @Override
708 public String toString() {
709 return String.format("import %s%s", type.equals("static") ? "static " : "", name);
710 }
711 }
712
Jan Lahodaa21102b2015-10-19 19:15:16 +0200713 class WaitingTestingInputStream extends TestingInputStream {
714
715 @Override
716 synchronized void setInput(String s) {
717 super.setInput(s);
718 notify();
719 }
720
721 synchronized void waitForInput() {
722 boolean interrupted = false;
723 try {
724 while (available() == 0) {
725 try {
726 wait();
727 } catch (InterruptedException e) {
728 interrupted = true;
729 // fall through and retry
730 }
731 }
732 } finally {
733 if (interrupted) {
734 Thread.currentThread().interrupt();
735 }
736 }
737 }
738
739 @Override
740 public int read() {
741 waitForInput();
742 return super.read();
743 }
744
745 @Override
746 public int read(byte b[], int off, int len) {
747 waitForInput();
748 return super.read(b, off, len);
749 }
750 }
751
752 class PromptedCommandOutputStream extends OutputStream {
753 private final ReplTest[] tests;
754 private int index = 0;
755 PromptedCommandOutputStream(ReplTest[] tests) {
756 this.tests = tests;
757 }
758
759 @Override
760 public synchronized void write(int b) {
761 if (b == 5 || b == 6) {
762 if (index < (tests.length - 1)) {
763 tests[index].run(true);
764 tests[index + 1].run(false);
765 } else {
766 fail("Did not exit Repl tool after test");
767 }
768 ++index;
769 } // For now, anything else is thrown away
770 }
771
772 @Override
773 public synchronized void write(byte b[], int off, int len) {
774 if ((off < 0) || (off > b.length) || (len < 0)
775 || ((off + len) - b.length > 0)) {
776 throw new IndexOutOfBoundsException();
777 }
778 for (int i = 0; i < len; ++i) {
779 write(b[off + i]);
780 }
781 }
782 }
Jan Lahodaa981a562016-03-23 13:40:42 +0100783
784 public static final class MemoryPreferences extends AbstractPreferences {
785
786 private final Map<String, String> values = new HashMap<>();
787 private final Map<String, MemoryPreferences> nodes = new HashMap<>();
788
789 public MemoryPreferences() {
790 this(null, "");
791 }
792
793 public MemoryPreferences(MemoryPreferences parent, String name) {
794 super(parent, name);
795 }
796
797 @Override
798 protected void putSpi(String key, String value) {
799 values.put(key, value);
800 }
801
802 @Override
803 protected String getSpi(String key) {
804 return values.get(key);
805 }
806
807 @Override
808 protected void removeSpi(String key) {
809 values.remove(key);
810 }
811
812 @Override
813 protected void removeNodeSpi() throws BackingStoreException {
814 ((MemoryPreferences) parent()).nodes.remove(name());
815 }
816
817 @Override
818 protected String[] keysSpi() throws BackingStoreException {
819 return values.keySet().toArray(new String[0]);
820 }
821
822 @Override
823 protected String[] childrenNamesSpi() throws BackingStoreException {
824 return nodes.keySet().toArray(new String[0]);
825 }
826
827 @Override
828 protected AbstractPreferences childSpi(String name) {
829 return nodes.computeIfAbsent(name, n -> new MemoryPreferences(this, name));
830 }
831
832 @Override
833 protected void syncSpi() throws BackingStoreException {
834 }
835
836 @Override
837 protected void flushSpi() throws BackingStoreException {
838 }
839
840 }
Jan Lahodaa21102b2015-10-19 19:15:16 +0200841}