/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.debug.tests.core; import java.util.ArrayList; import java.util.List; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.IStreamsProxy; import org.eclipse.debug.core.model.IStreamsProxy2; import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.ui.console.IConsole; import org.eclipse.debug.ui.console.IConsoleLineTrackerExtension; import org.eclipse.jdt.debug.testplugin.ConsoleLineTracker; import org.eclipse.jdt.debug.tests.AbstractDebugTest; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.swt.widgets.Display; import org.eclipse.test.OrderedTestSuite; import junit.framework.TestSuite; /** * Tests console input. */ public class ConsoleInputTests extends AbstractDebugTest implements IConsoleLineTrackerExtension { protected List<String> fLinesRead = new ArrayList<String>(); protected boolean fStarted = false; protected boolean fStopped = false; protected IConsole fConsole = null; protected Object fConsoleLock = new Object(); protected Object fLock = new Object(); public static TestSuite suite() { return new OrderedTestSuite(ConsoleInputTests.class, new String[] { "testMultiLineInput", "testEOF", "testDeleteAllEnteredText" }); } public ConsoleInputTests(String name) { super(name); } @Override protected void setUp() throws Exception { super.setUp(); fStarted = false; fStopped = false; } /** * Writes text to the console with line feeds (like pasting multiple lines). * The lines with line delimiters should be echoed back. The text remaining * on the last line (without a line delimiter) should remain in the input * buffer until it is ended with a line delimiter. */ public void testMultiLineInput() throws Exception { ConsoleLineTracker.setDelegate(this); ILaunchConfiguration configuration = getLaunchConfiguration("ConsoleInput"); ILaunch launch = null; try { launch = configuration.launch(ILaunchManager.RUN_MODE, null); synchronized (fConsoleLock) { if (!fStarted) { fConsoleLock.wait(30000); } } assertNotNull("Console is null", fConsole); String[] list = appendAndGet(fConsole, "one\ntwo\nexit", 4); verifyOutput(new String[]{"one", "two", "exitone", "two"}, list); // end the program list = appendAndGet(fConsole, "three\n", 3); verifyOutput(new String[]{"three", "exitthree", IInternalDebugCoreConstants.EMPTY_STRING}, list); } finally { ConsoleLineTracker.setDelegate(null); launch.getProcesses()[0].terminate(); } } /** * Tests closing standard in */ public void testEOF() throws Exception { ConsoleLineTracker.setDelegate(this); ILaunchConfiguration configuration = getLaunchConfiguration("ConsoleInput"); ILaunch launch = null; try { launch = configuration.launch(ILaunchManager.RUN_MODE, null); synchronized (fConsoleLock) { if (!fStarted) { fConsoleLock.wait(30000); } } assertNotNull("Console is null", fConsole); String[] list = appendAndGet(fConsole, "one\ntwo\n", 4); verifyOutput(new String[]{"one", "two", "one", "two"}, list); // send EOF IStreamsProxy streamsProxy = launch.getProcesses()[0].getStreamsProxy(); assertTrue("should be an IStreamsProxy2", streamsProxy instanceof IStreamsProxy2); IStreamsProxy2 proxy2 = (IStreamsProxy2)streamsProxy; fLinesRead.clear(); proxy2.closeInputStream(); int attempts = 0; while (fLinesRead.size() < 2) { spinEventLoop(); synchronized (fLinesRead) { if (fLinesRead.size() < 2) { fLinesRead.wait(200); } } attempts++; if (attempts > 150) { break; } } assertEquals("Wrong number of lines", 2, fLinesRead.size()); assertEquals("Should be EOF message", "EOF", fLinesRead.get(0)); assertEquals("Should be empty line", IInternalDebugCoreConstants.EMPTY_STRING, fLinesRead.get(1)); } finally { ConsoleLineTracker.setDelegate(null); launch.getProcesses()[0].terminate(); } } private void verifyOutput(String[] expected, String[] actual) { for (int i = 0; i < actual.length; i++) { assertEquals("Wrong message", expected[i], actual[i]); } } /** * Appends the given text to the given console and waits for the number * of lines to be written to the console. Returns the lines written to * the console. * * @param console * @param text * @param linesExpected * @return lines written to the console without line delimiters * @throws Exception */ private String[] appendAndGet(IConsole console, final String text, int linesExpected) throws Exception { fLinesRead.clear(); final IDocument document = console.getDocument(); DebugUIPlugin.getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { try { document.replace(document.getLength(), 0, text); } catch (BadLocationException e) { e.printStackTrace(); } } }); int attempts = 0; while (fLinesRead.size() < linesExpected) { spinEventLoop(); synchronized (fLinesRead) { if (fLinesRead.size() < linesExpected) { fLinesRead.wait(200); } } attempts++; if (attempts > 150) { break; } } assertEquals("Wrong number of lines", linesExpected, fLinesRead.size()); return fLinesRead.toArray(new String[0]); } /** * Appends the given text to the given console. Text should not have new lines. * * @param console * @param text * @throws Exception */ private void append(IConsole console, final String text) throws Exception { final IDocument document = console.getDocument(); DebugUIPlugin.getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { try { document.replace(document.getLength(), 0, text); } catch (BadLocationException e) { e.printStackTrace(); } } }); spinEventLoop(); } /** * Deletes all text in the given console. * * @param console * @throws Exception */ private void deleteAll(IConsole console) throws Exception { final IDocument document = console.getDocument(); DebugUIPlugin.getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { try { document.replace(0, document.getLength(), ""); } catch (BadLocationException e) { e.printStackTrace(); } } }); spinEventLoop(); } /** * @see org.eclipse.debug.ui.console.IConsoleLineTracker#dispose() */ @Override public void dispose() { } /** * @see org.eclipse.debug.ui.console.IConsoleLineTracker#init(org.eclipse.debug.ui.console.IConsole) */ @Override public void init(IConsole console) { synchronized (fConsoleLock) { fConsole = console; fStarted = true; fConsoleLock.notifyAll(); } } /** * @see org.eclipse.debug.ui.console.IConsoleLineTracker#lineAppended(org.eclipse.jface.text.IRegion) */ @Override public void lineAppended(IRegion line) { if (fStarted) { synchronized (fLinesRead) { try { String text = fConsole.getDocument().get(line.getOffset(), line.getLength()); fLinesRead.add(text); } catch (BadLocationException e) { e.printStackTrace(); } fLinesRead.notifyAll(); } } } /** * @see org.eclipse.debug.ui.console.IConsoleLineTracker#streamClosed() */ @Override public void consoleClosed() { synchronized (fLock) { fStopped = true; fLock.notifyAll(); } } /** * Tests the scenario reported in bug 241394 - 'a', backspace, 'b', backspace, 'c', Enter. * Result should be 'c'. * * @throws Exception */ public void testDeleteAllEnteredText() throws Exception { ConsoleLineTracker.setDelegate(this); ILaunchConfiguration configuration = getLaunchConfiguration("ConsoleInput"); ILaunch launch = null; try { launch = configuration.launch(ILaunchManager.RUN_MODE, null); synchronized (fConsoleLock) { if (!fStarted) { fConsoleLock.wait(30000); } } assertNotNull("Console is null", fConsole); append(fConsole, "a"); deleteAll(fConsole); append(fConsole, "b"); deleteAll(fConsole); String[] list = appendAndGet(fConsole, "c\n", 2); verifyOutput(new String[]{"c", "c"}, list); } finally { ConsoleLineTracker.setDelegate(null); launch.getProcesses()[0].terminate(); } } private void spinEventLoop() { final Display display= DebugUIPlugin.getStandardDisplay(); Runnable runnable= new Runnable() { @Override public void run() { while (display.readAndDispatch()) { } } }; if (Display.getCurrent() == display) { runnable.run(); } else { display.syncExec(runnable); } } }