package terminal; import static org.junit.Assert.*; import static terminal.LispTerminal.END_OF_SEGMENT; import java.io.*; import org.junit.*; import com.googlecode.lanterna.*; import com.googlecode.lanterna.input.*; import com.googlecode.lanterna.terminal.virtual.*; public class LispTerminalTest { private PipedInputStream inputReader; private PipedOutputStream inputWriter; private PipedInputStream outputReader; private PipedOutputStream outputWriter; private FlushListener flushListener; private VirtualTerminal virtualTerminal; private LispTerminal lispTerminal; private void pressKey(KeyType keyType) { virtualTerminal.addInput(new KeyStroke(keyType)); waitForFlushes(1); } private void pressControlKey(KeyType keyType) { virtualTerminal.addInput(new KeyStroke(keyType, true, false)); waitForFlushes(1); } private void enterCharacter(char character) { virtualTerminal.addInput(new KeyStroke(character, false, false)); waitForFlushes(1); } private void enterControlCharacter(char character) { virtualTerminal.addInput(new KeyStroke(character, true, false)); waitForFlushes(1); } private void enterCharacters(String characters) { for (char c : characters.toCharArray()) virtualTerminal.addInput(new KeyStroke(c, false, false)); waitForFlushes(characters.length()); } private void produceOutput(String output) { try { for (char c : output.toCharArray()) outputWriter.write(c); outputWriter.write(END_OF_SEGMENT); outputWriter.flush(); waitForFlushes(1); } catch (IOException e) {} } private void waitForFlushes(int flushCount) { try { synchronized (flushListener) { while (flushListener.getFlushCount() < flushCount) flushListener.wait(); flushListener.resetFlushCount(); } } catch (InterruptedException e) {} } private void setColumns(int columns) { virtualTerminal.setTerminalSize(new TerminalSize(columns, virtualTerminal.getTerminalSize().getRows())); } private void setRows(int rows) { virtualTerminal.setTerminalSize(new TerminalSize(virtualTerminal.getTerminalSize().getColumns(), rows)); } private void assertCursorPosition(int column, int row) { assertEquals(column, virtualTerminal.getCursorPosition().getColumn()); assertEquals(row, virtualTerminal.getCursorPosition().getRow()); } private void assertCharacterAtPosition(char character, int column, int row) { TerminalPosition position = new TerminalPosition(column, row); assertEquals(character, virtualTerminal.getCharacter(position).getCharacter()); } private void assertInputWritten(String expected) { String actual = ""; try { inputWriter.close(); for (int c = inputReader.read(); c != -1; c = inputReader.read()) { actual += (char) c; } } catch (IOException e) {} assertEquals(expected, actual); } private void assertInputStreamClosed() { try { inputWriter.write(0); fail("input stream not closed"); } catch (IOException e) {} } @Before public void setUp() throws IOException { inputReader = new PipedInputStream(); inputWriter = new PipedOutputStream(inputReader); outputReader = new PipedInputStream(); outputWriter = new PipedOutputStream(outputReader); virtualTerminal = new DefaultVirtualTerminal(); flushListener = new FlushListener(); virtualTerminal.addVirtualTerminalListener(flushListener); lispTerminal = new LispTerminal(virtualTerminal, inputWriter, outputReader); lispTerminal.run(); } @After public void tearDown() throws IOException { lispTerminal.finish(); outputWriter.close(); } @Test public void leftArrowDoesNotMovePastOrigin() { pressKey(KeyType.ArrowLeft); assertCursorPosition(0, 0); } @Test public void leftArrowWorksAfterEnteringCharacters() { enterCharacters("abc"); assertCursorPosition(3, 0); pressKey(KeyType.ArrowLeft); assertCursorPosition(2, 0); pressKey(KeyType.ArrowLeft); assertCursorPosition(1, 0); pressKey(KeyType.ArrowLeft); assertCursorPosition(0, 0); pressKey(KeyType.ArrowLeft); assertCursorPosition(0, 0); } @Test public void leftArrowWorksAcrossRows() { setColumns(5); enterCharacters("123451"); assertCursorPosition(1, 1); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); assertCursorPosition(4, 0); } @Test public void rightArrowDoesNotMovePastEndOfInput() { pressKey(KeyType.ArrowRight); assertCursorPosition(0, 0); } @Test public void rightArrowWorksAfterMovingLeft() { enterCharacters("12"); assertCursorPosition(2, 0); pressKey(KeyType.ArrowLeft); assertCursorPosition(1, 0); pressKey(KeyType.ArrowRight); assertCursorPosition(2, 0); pressKey(KeyType.ArrowRight); assertCursorPosition(2, 0); } @Test public void rightArrowWorksAcrossRow() { setColumns(5); enterCharacters("123451"); assertCursorPosition(1, 1); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); assertCursorPosition(3, 0); pressKey(KeyType.ArrowRight); pressKey(KeyType.ArrowRight); pressKey(KeyType.ArrowRight); assertCursorPosition(1, 1); } @Test public void characterKeyIsEchoed() { enterCharacter('a'); assertCursorPosition(1, 0); assertCharacterAtPosition('a', 0, 0); } @Test public void characterIsInserted() { enterCharacters("abcd"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); enterCharacter('x'); assertCharacterAtPosition('a', 0, 0); assertCharacterAtPosition('b', 1, 0); assertCharacterAtPosition('x', 2, 0); assertCharacterAtPosition('c', 3, 0); assertCharacterAtPosition('d', 4, 0); } @Test public void characterIsInserted_PushesInputToNextRow() { setColumns(4); enterCharacters("abcd"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); enterCharacter('x'); assertCharacterAtPosition('a', 0, 0); assertCharacterAtPosition('b', 1, 0); assertCharacterAtPosition('x', 2, 0); assertCharacterAtPosition('c', 3, 0); assertCharacterAtPosition('d', 0, 1); } @Test public void backspaceDoesNothingAtOrigin() { pressKey(KeyType.Backspace); assertCursorPosition(0, 0); } @Test public void backspaceWorksAfterInput() { enterCharacters("12345"); pressKey(KeyType.Backspace); pressKey(KeyType.Backspace); assertCursorPosition(3, 0); assertCharacterAtPosition('1', 0, 0); assertCharacterAtPosition('2', 1, 0); assertCharacterAtPosition('3', 2, 0); assertCharacterAtPosition(' ', 3, 0); assertCharacterAtPosition(' ', 4, 0); assertCharacterAtPosition(' ', 5, 0); } @Test public void backspaceWorksAcrossRow() { setColumns(4); enterCharacters("1234567"); pressKey(KeyType.Backspace); pressKey(KeyType.Backspace); pressKey(KeyType.Backspace); pressKey(KeyType.Backspace); pressKey(KeyType.Backspace); assertCursorPosition(2, 0); assertCharacterAtPosition('1', 0, 0); assertCharacterAtPosition('2', 1, 0); assertCharacterAtPosition(' ', 2, 0); assertCharacterAtPosition(' ', 3, 0); assertCharacterAtPosition(' ', 0, 1); assertCharacterAtPosition(' ', 1, 1); assertCharacterAtPosition(' ', 2, 1); } @Test public void backspaceWorksInMiddleOfInput() { enterCharacters("12345"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.Backspace); assertCursorPosition(2, 0); assertCharacterAtPosition('1', 0, 0); assertCharacterAtPosition('2', 1, 0); assertCharacterAtPosition('4', 2, 0); assertCharacterAtPosition('5', 3, 0); } @Test public void deleteDoesNothingAtOrigin() { pressKey(KeyType.Delete); assertCursorPosition(0, 0); } @Test public void deleteDoesNothingAtEndOfInput() { enterCharacters("del"); pressKey(KeyType.Delete); assertCursorPosition(3, 0); assertCharacterAtPosition('d', 0, 0); assertCharacterAtPosition('e', 1, 0); assertCharacterAtPosition('l', 2, 0); } @Test public void deleteWorksAtStartOfInput() { enterCharacters("del"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.Delete); pressKey(KeyType.Delete); pressKey(KeyType.Delete); assertCursorPosition(0, 0); assertCharacterAtPosition(' ', 0, 0); assertCharacterAtPosition(' ', 1, 0); assertCharacterAtPosition(' ', 2, 0); } @Test public void deleteWorksAcrossRow() { setColumns(4); enterCharacters("delete"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.Delete); assertCursorPosition(1, 0); assertCharacterAtPosition('d', 0, 0); assertCharacterAtPosition('l', 1, 0); assertCharacterAtPosition('e', 2, 0); assertCharacterAtPosition('t', 3, 0); assertCharacterAtPosition('e', 0, 1); assertCharacterAtPosition(' ', 1, 1); } @Test public void enterMovesToNextLine() { pressKey(KeyType.Enter); assertCursorPosition(0, 1); } @Test public void enterWritesLineToPipedStream() { enterCharacters("enter"); pressKey(KeyType.Enter); assertInputWritten("enter\n"); } @Test public void enterPressedInMiddleOfInput_WritesEntireLineToPipedStream() { enterCharacters("enter"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.Enter); assertInputWritten("enter\n"); } @Test public void controlDWorks() { enterCharacters("control-d"); enterControlCharacter('d'); assertInputStreamClosed(); assertInputWritten("control-d\n"); } @Test public void controlDWorksInMiddleOfInput() { enterCharacters("control-d"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); enterControlCharacter('d'); assertInputStreamClosed(); assertInputWritten("control-d\n"); } @Test public void escapeDoesNothing() { pressKey(KeyType.Escape); assertCursorPosition(0, 0); assertInputWritten(""); } @Test public void controlQDoesNothing() { enterControlCharacter('q'); assertCursorPosition(0, 0); assertInputWritten(""); } @Test public void controlEnterDoesNothing() { pressControlKey(KeyType.Enter); assertCursorPosition(0, 0); assertInputWritten(""); } @Test public void outputIsWritten() { produceOutput("output"); assertCursorPosition(6, 0); assertCharacterAtPosition('o', 0, 0); assertCharacterAtPosition('u', 1, 0); assertCharacterAtPosition('t', 2, 0); assertCharacterAtPosition('p', 3, 0); assertCharacterAtPosition('u', 4, 0); assertCharacterAtPosition('t', 5, 0); } @Test public void endOfSegmentCharacterIsNotPrinted() { produceOutput("> " + END_OF_SEGMENT); assertCursorPosition(2, 0); assertCharacterAtPosition('>', 0, 0); assertCharacterAtPosition(' ', 1, 0); assertCharacterAtPosition(' ', 2, 0); } @Test public void enterTextPastLastLineOfBuffer() { setColumns(3); setRows(2); enterCharacters("01201201"); assertCursorPosition(2, 1); assertCharacterAtPosition('0', 0, 0); assertCharacterAtPosition('1', 1, 0); assertCharacterAtPosition('2', 2, 0); assertCharacterAtPosition('0', 0, 1); assertCharacterAtPosition('1', 1, 1); } // @Test // public void insertingTextPushesInputPastEndOfBuffer() { // setColumns(2); // setRows(3); // enterCharacters("00112"); // // pressKey(KeyType.ArrowLeft); // pressKey(KeyType.ArrowLeft); // pressKey(KeyType.ArrowLeft); // enterCharacters("zz"); // assertCursorPosition(0, 1); // assertCharacterAtPosition('z', 0, 0); // assertCharacterAtPosition('z', 1, 0); // assertCharacterAtPosition('1', 0, 1); // assertCharacterAtPosition('1', 1, 1); // assertCharacterAtPosition('2', 0, 2); // } @Test public void printedOutputToEndOfRow_MovesCursorToNextRow() { setColumns(3); produceOutput("out"); assertCursorPosition(0, 1); } @Test public void printedOutputToEndOfBuffer_MovesCursorToNewRow() { setColumns(3); setRows(2); produceOutput("output"); assertCursorPosition(0, 1); assertCharacterAtPosition('p', 0, 0); assertCharacterAtPosition('u', 1, 0); assertCharacterAtPosition('t', 2, 0); assertCharacterAtPosition(' ', 0, 1); assertCharacterAtPosition(' ', 1, 1); assertCharacterAtPosition(' ', 2, 1); } @Test public void printedOutputDoesNotOverwriteInput() { setColumns(3); enterCharacters("01201201"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); produceOutput("out"); assertCursorPosition(0, 4); assertCharacterAtPosition('0', 0, 0); assertCharacterAtPosition('1', 1, 0); assertCharacterAtPosition('2', 2, 0); assertCharacterAtPosition('0', 0, 1); assertCharacterAtPosition('1', 1, 1); assertCharacterAtPosition('2', 2, 1); assertCharacterAtPosition('0', 0, 2); assertCharacterAtPosition('1', 1, 2); assertCharacterAtPosition('o', 2, 2); assertCharacterAtPosition('u', 0, 3); assertCharacterAtPosition('t', 1, 3); assertCharacterAtPosition(' ', 2, 3); } @Test public void printedOutputDoesNotOverwriteInput_AfterEnter() { setColumns(3); enterCharacters("01201201"); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.ArrowLeft); pressKey(KeyType.Enter); produceOutput("out"); assertCursorPosition(0, 4); assertCharacterAtPosition('0', 0, 0); assertCharacterAtPosition('1', 1, 0); assertCharacterAtPosition('2', 2, 0); assertCharacterAtPosition('0', 0, 1); assertCharacterAtPosition('1', 1, 1); assertCharacterAtPosition('2', 2, 1); assertCharacterAtPosition('0', 0, 2); assertCharacterAtPosition('1', 1, 2); assertCharacterAtPosition(' ', 2, 2); assertCharacterAtPosition('o', 0, 3); assertCharacterAtPosition('u', 1, 3); assertCharacterAtPosition('t', 2, 3); } }