package terminal; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static terminal.LispTerminal.END_OF_SEGMENT; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; import com.googlecode.lanterna.TerminalPosition; import com.googlecode.lanterna.TerminalSize; import com.googlecode.lanterna.input.KeyStroke; import com.googlecode.lanterna.input.KeyType; import com.googlecode.lanterna.terminal.virtual.DefaultVirtualTerminal; import com.googlecode.lanterna.terminal.virtual.VirtualTerminal; import stream.UncheckedIOException; public class VirtualTerminalInteractor { private PipedOutputStream inputWriter; private PipedInputStream inputReader; private PipedOutputStream outputWriter; private PipedInputStream outputReader; private VirtualTerminal virtualTerminal; private FlushListener flushListener; private LispTerminal lispTerminal; private TerminalConfiguration configuration; public VirtualTerminalInteractor() { this.inputWriter = new PipedOutputStream(); this.inputReader = new PipedInputStream(); this.outputWriter = new PipedOutputStream(); this.outputReader = new PipedInputStream(); this.virtualTerminal = new DefaultVirtualTerminal(); this.flushListener = new FlushListener(); this.virtualTerminal.addVirtualTerminalListener(flushListener); this.lispTerminal = new LispTerminal(createTerminalConfiguration()); } private TerminalConfiguration createTerminalConfiguration() { configuration = new TerminalConfiguration(); configuration.setInputPair(inputWriter, inputReader); configuration.setOutputPair(outputWriter, outputReader); configuration.setTerminal(virtualTerminal); return configuration; } public TerminalConfiguration getConfiguration() { return configuration; } public void start() { lispTerminal.start(); } public void stop() { try { lispTerminal.stop(); outputWriter.close(); } catch (IOException e) { throw new UncheckedIOException(e); } } public void pressKey(KeyType keyType) { virtualTerminal.addInput(new KeyStroke(keyType)); waitForFlushes(1); } public void pressKeyTimes(KeyType keyType, int times) { for (int i = times; i > 0; i--) virtualTerminal.addInput(new KeyStroke(keyType)); waitForFlushes(times); } public void pressControlKey(KeyType keyType) { virtualTerminal.addInput(new KeyStroke(keyType, true, false)); waitForFlushes(1); } public void enterCharacter(char character) { virtualTerminal.addInput(new KeyStroke(character, false, false)); waitForFlushes(1); } public void enterControlCharacter(char character) { virtualTerminal.addInput(new KeyStroke(character, true, false)); waitForFlushes(1); } public void enterCharacters(String characters) { for (char c : characters.toCharArray()) virtualTerminal.addInput(new KeyStroke(c, false, false)); waitForFlushes(characters.length()); } public void produceOutput(String output) { try { for (char c : output.toCharArray()) outputWriter.write(c); outputWriter.write(END_OF_SEGMENT); outputWriter.flush(); waitForFlushes(1); } catch (IOException ignored) {} } public void waitForFlushes(int flushCount) { try { synchronized (flushListener) { while (flushListener.getFlushCount() < flushCount) flushListener.wait(); flushListener.reduceFlushCount(flushCount); } } catch (InterruptedException ignored) {} } public void waitForPrompt() { waitForFlushes(1); } public void setColumns(int columns) { int rows = virtualTerminal.getTerminalSize().getRows(); virtualTerminal.setTerminalSize(new TerminalSize(columns, rows)); } public void setRows(int rows) { int columns = virtualTerminal.getTerminalSize().getColumns(); virtualTerminal.setTerminalSize(new TerminalSize(columns, rows)); } public void assertCursorPosition(int column, int row) { assertThat(virtualTerminal.getCursorPosition().getColumn(), is(column)); assertThat(virtualTerminal.getCursorPosition().getRow(), is(row)); } public void assertScreenText(String... rows) { for (int row = 0; row < rows.length; row++) for (int column = 0; column < rows[row].length(); column++) assertCharacterAtPosition(rows[row].charAt(column), column, row); } public void assertCharacterAtPosition(char character, int column, int row) { TerminalPosition position = new TerminalPosition(column, row); String expected = String.valueOf(character); String actual = String.valueOf(virtualTerminal.getCharacter(position).getCharacter()); assertThat(actual, is(expected)); } public void assertInputWritten(String expected) { String actual = ""; try { inputWriter.close(); for (int c = inputReader.read(); c != -1; c = inputReader.read()) actual += (char) c; } catch (IOException ignored) {} assertThat(actual, is(expected)); } public void assertInputStreamClosed() { try { inputWriter.write(0); fail("input stream not closed"); } catch (IOException ignored) {} } }