/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @summary Test Completion * @build HistoryTest * @run testng HistoryTest */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.prefs.AbstractPreferences; import java.util.prefs.BackingStoreException; import jdk.internal.jline.console.history.MemoryHistory; import jdk.jshell.JShell; import jdk.jshell.SourceCodeAnalysis; import jdk.jshell.SourceCodeAnalysis.CompletionInfo; import org.testng.annotations.Test; import jdk.internal.jshell.tool.EditingHistory; import static org.testng.Assert.*; @Test public class HistoryTest { public void testHistory() { JShell eval = JShell.builder() .in(new ByteArrayInputStream(new byte[0])) .out(new PrintStream(new ByteArrayOutputStream())) .err(new PrintStream(new ByteArrayOutputStream())) .build(); SourceCodeAnalysis analysis = eval.sourceCodeAnalysis(); MemoryPreferences prefs = new MemoryPreferences(null, ""); EditingHistory history = new EditingHistory(prefs) { @Override protected CompletionInfo analyzeCompletion(String input) { return analysis.analyzeCompletion(input); } }; history.add("void test() {"); history.add(" System.err.println(1);"); history.add("}"); history.add("/exit"); previousAndAssert(history, "/exit"); history.previous(); history.previous(); history.previous(); history.add("void test() { /*changed*/"); previousAndAssert(history, "}"); previousAndAssert(history, " System.err.println(1);"); previousAndAssert(history, "void test() {"); assertFalse(history.previous()); nextAndAssert(history, " System.err.println(1);"); nextAndAssert(history, "}"); nextAndAssert(history, ""); history.add(" System.err.println(2);"); history.add("} /*changed*/"); assertEquals(history.size(), 7); history.save(); history = new EditingHistory(prefs) { @Override protected CompletionInfo analyzeCompletion(String input) { return analysis.analyzeCompletion(input); } }; previousSnippetAndAssert(history, "void test() { /*changed*/"); previousSnippetAndAssert(history, "/exit"); previousSnippetAndAssert(history, "void test() {"); assertFalse(history.previousSnippet()); nextSnippetAndAssert(history, "/exit"); nextSnippetAndAssert(history, "void test() { /*changed*/"); nextSnippetAndAssert(history, ""); assertFalse(history.nextSnippet()); history.add("{"); history.add("}"); history.save(); history = new EditingHistory(prefs) { @Override protected CompletionInfo analyzeCompletion(String input) { return analysis.analyzeCompletion(input); } }; previousSnippetAndAssert(history, "{"); previousSnippetAndAssert(history, "void test() { /*changed*/"); previousSnippetAndAssert(history, "/exit"); previousSnippetAndAssert(history, "void test() {"); while (history.next()); history.add("/*current1*/"); history.add("/*current2*/"); history.add("/*current3*/"); assertEquals(history.currentSessionEntries(), Arrays.asList("/*current1*/", "/*current2*/", "/*current3*/")); history.remove(0); assertEquals(history.currentSessionEntries(), Arrays.asList("/*current1*/", "/*current2*/", "/*current3*/")); while (history.size() > 2) history.remove(0); assertEquals(history.currentSessionEntries(), Arrays.asList("/*current2*/", "/*current3*/")); for (int i = 0; i < MemoryHistory.DEFAULT_MAX_SIZE * 2; i++) { history.add("/exit"); } history.add("void test() { /*after full*/"); history.add(" System.err.println(1);"); history.add("}"); previousSnippetAndAssert(history, "void test() { /*after full*/"); } public void testSaveOneHistory() { JShell eval = JShell.builder() .in(new ByteArrayInputStream(new byte[0])) .out(new PrintStream(new ByteArrayOutputStream())) .err(new PrintStream(new ByteArrayOutputStream())) .build(); SourceCodeAnalysis analysis = eval.sourceCodeAnalysis(); MemoryPreferences prefs = new MemoryPreferences(null, ""); EditingHistory history = new EditingHistory(prefs) { @Override protected CompletionInfo analyzeCompletion(String input) { return analysis.analyzeCompletion(input); } }; history.add("first"); history.save(); } private void previousAndAssert(EditingHistory history, String expected) { assertTrue(history.previous()); assertEquals(history.current().toString(), expected); } private void nextAndAssert(EditingHistory history, String expected) { assertTrue(history.next()); assertEquals(history.current().toString(), expected); } private void previousSnippetAndAssert(EditingHistory history, String expected) { assertTrue(history.previousSnippet()); assertEquals(history.current().toString(), expected); } private void nextSnippetAndAssert(EditingHistory history, String expected) { assertTrue(history.nextSnippet()); assertEquals(history.current().toString(), expected); } private static final class MemoryPreferences extends AbstractPreferences { private final Map key2Value = new HashMap<>(); private final Map key2SubNode = new HashMap<>(); public MemoryPreferences(AbstractPreferences parent, String name) { super(parent, name); } @Override protected void putSpi(String key, String value) { key2Value.put(key, value); } @Override protected String getSpi(String key) { return key2Value.get(key); } @Override protected void removeSpi(String key) { key2Value.remove(key); } @Override protected void removeNodeSpi() throws BackingStoreException { ((MemoryPreferences) parent()).key2SubNode.remove(name()); } @Override protected String[] keysSpi() throws BackingStoreException { return key2Value.keySet().toArray(new String[key2Value.size()]); } @Override protected String[] childrenNamesSpi() throws BackingStoreException { return key2SubNode.keySet().toArray(new String[key2SubNode.size()]); } @Override protected AbstractPreferences childSpi(String name) { return key2SubNode.computeIfAbsent(name, n -> new MemoryPreferences(this, n)); } @Override protected void syncSpi() throws BackingStoreException {} @Override protected void flushSpi() throws BackingStoreException {} } }