Increase test coverage and refactor code

This commit is contained in:
Mike Cifelli 2017-03-23 12:14:44 -04:00
parent 79fb8b633b
commit 23dd1c0654
25 changed files with 350 additions and 101 deletions

View File

@ -1,9 +1,9 @@
package error;
import static error.ErrorManager.Severity.*;
import static java.text.MessageFormat.format;
import java.io.PrintStream;
import java.text.MessageFormat;
import environment.RuntimeEnvironment;
@ -40,7 +40,7 @@ public class ErrorManager {
private String formatMessage(LispException lispException) {
Severity severity = lispException.getSeverity();
String prefix = severity.toDisplayString();
String message = MessageFormat.format("[{0}] {1}", prefix, lispException.getMessage());
String message = format("[{0}] {1}", prefix, lispException.getMessage());
return severity.decorate(message, environment);
}

View File

@ -1,6 +1,6 @@
package error;
import java.text.MessageFormat;
import static java.text.MessageFormat.format;
import file.FilePosition;
@ -15,8 +15,8 @@ public abstract class LineColumnException extends LispException {
@Override
public String getMessage() {
return MessageFormat.format("{0} - line {1}, column {2}", getMessagePrefix(), position.getLineNumber(),
position.getColumnNumber());
return format("{0} - line {1}, column {2}", getMessagePrefix(), position.getLineNumber(),
position.getColumnNumber());
}
public abstract String getMessagePrefix();

View File

@ -1,9 +1,9 @@
package function;
import static function.builtin.cons.LENGTH.getLength;
import static java.text.MessageFormat.format;
import java.math.BigInteger;
import java.text.MessageFormat;
import error.LispException;
import sexpression.*;
@ -163,7 +163,7 @@ public class ArgumentValidator {
@Override
public String getMessage() {
return MessageFormat.format("too few arguments given to {0}: {1}", functionName, argumentList);
return format("too few arguments given to {0}: {1}", functionName, argumentList);
}
}
@ -180,7 +180,7 @@ public class ArgumentValidator {
@Override
public String getMessage() {
return MessageFormat.format("too many arguments given to {0}: {1}", functionName, argumentList);
return format("too many arguments given to {0}: {1}", functionName, argumentList);
}
}
@ -197,7 +197,7 @@ public class ArgumentValidator {
@Override
public String getMessage() {
return MessageFormat.format("dotted argument list given to {0}: {1}", functionName, argumentList);
return format("dotted argument list given to {0}: {1}", functionName, argumentList);
}
}
@ -217,8 +217,8 @@ public class ArgumentValidator {
@Override
public String getMessage() {
return MessageFormat.format("{0}: {1} is not the expected type of ''{2}''", functionName, argument,
getExpectedTypeName());
return format("{0}: {1} is not the expected type of ''{2}''", functionName, argument,
getExpectedTypeName());
}
private String getExpectedTypeName() {

View File

@ -1,9 +1,9 @@
package function;
import static function.builtin.EVAL.eval;
import static java.text.MessageFormat.format;
import static sexpression.Nil.NIL;
import java.text.MessageFormat;
import java.util.ArrayList;
import error.LispException;
@ -140,8 +140,8 @@ public class UserDefinedFunction extends LispFunction {
@Override
public String getMessage() {
return MessageFormat.format("unexpected parameters following ''&rest'' in definition of {0}: {1}",
functionName, parameters);
return format("unexpected parameters following ''&rest'' in definition of {0}: {1}", functionName,
parameters);
}
}

View File

@ -2,12 +2,11 @@ package function.builtin;
import static function.builtin.cons.LIST.makeList;
import static function.builtin.special.LAMBDA.*;
import static java.text.MessageFormat.format;
import static sexpression.Nil.NIL;
import static sexpression.Symbol.T;
import static table.FunctionTable.lookupFunction;
import java.text.MessageFormat;
import error.LispException;
import function.*;
import sexpression.*;
@ -150,7 +149,7 @@ public class EVAL extends LispFunction {
@Override
public String getMessage() {
return MessageFormat.format("undefined function: {0}", function);
return format("undefined function: {0}", function);
}
}
@ -165,7 +164,7 @@ public class EVAL extends LispFunction {
@Override
public String getMessage() {
return MessageFormat.format("symbol {0} has no value", symbol);
return format("symbol {0} has no value", symbol);
}
}

View File

@ -1,12 +1,12 @@
package function.builtin;
import static function.builtin.EVAL.eval;
import static java.text.MessageFormat.format;
import static sexpression.Nil.NIL;
import static sexpression.Symbol.T;
import static util.Path.getPathPrefix;
import java.io.*;
import java.text.MessageFormat;
import java.util.Stack;
import environment.RuntimeEnvironment;
@ -105,7 +105,7 @@ public class LOAD extends LispFunction {
@Override
public String getMessage() {
return MessageFormat.format("could not load ''{0}''", fileName);
return format("could not load ''{0}''", fileName);
}
}

View File

@ -1,9 +1,8 @@
package function.builtin;
import static java.text.MessageFormat.format;
import static table.FunctionTable.lookupFunction;
import java.text.MessageFormat;
import error.LispException;
import function.*;
import sexpression.*;
@ -38,7 +37,7 @@ public class SYMBOL_FUNCTION extends LispFunction {
String typeIndicator = function instanceof LispSpecialFunction ? "SPECIAL-FUNCTION" : "FUNCTION";
return new Symbol(MessageFormat.format("#<{0} {1}>", typeIndicator, symbol));
return new Symbol(format("#<{0} {1}>", typeIndicator, symbol));
}
public static class UndefinedSymbolFunctionException extends LispException {
@ -52,7 +51,7 @@ public class SYMBOL_FUNCTION extends LispFunction {
@Override
public String getMessage() {
return MessageFormat.format("SYMBOL-FUNCTION: undefined function: {0}", function);
return format("SYMBOL-FUNCTION: undefined function: {0}", function);
}
}

View File

@ -1,10 +1,9 @@
package function.builtin.special;
import static function.builtin.cons.LIST.makeList;
import static java.text.MessageFormat.format;
import static table.FunctionTable.*;
import java.text.MessageFormat;
import environment.RuntimeEnvironment;
import error.LispWarning;
import function.*;
@ -67,7 +66,7 @@ public abstract class Define extends LispSpecialFunction {
@Override
public String getMessage() {
return MessageFormat.format("redefining function {0}", functionName);
return format("redefining function {0}", functionName);
}
}

View File

@ -2,7 +2,7 @@ package interpreter;
public class InteractiveLispInterpreter extends LispInterpreter {
private static final String PROMPT = "~ ";
public static final String PROMPT = "~ ";
@Override
protected void prompt() {

View File

@ -1,5 +1,6 @@
package main;
import static com.googlecode.lanterna.terminal.IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter;
import static terminal.LispTerminal.END_OF_SEGMENT;
import java.io.*;
@ -8,7 +9,6 @@ import java.util.function.Function;
import com.googlecode.lanterna.terminal.*;
import interpreter.*;
import stream.SafeOutputStream;
import terminal.LispTerminal;
public class LispMain {
@ -30,58 +30,76 @@ public class LispMain {
lispMain.runWithFile(arguments[0]);
}
private LispInterpreterBuilder builder;
private PipedInputStream inputReader;
private PipedOutputStream inputWriter;
private PipedInputStream outputReader;
private PipedOutputStream outputWriter;
private PrintStream outputStream;
private SafeOutputStream safeOutputWriter;
private PrintStream output;
private LispTerminal lispTerminal;
private void runInteractive() {
initializeTerminalAndStreams();
printGreeting();
lispTerminal.start();
buildInteractiveInterpreter().interpret();
outputStream.close();
public LispMain() {
this.builder = LispInterpreterBuilderImpl.getInstance();
TerminalConfiguration terminalConfiguration = new TerminalConfiguration();
terminalConfiguration.setInputWriter(new PipedOutputStream());
terminalConfiguration.setOutputReader(new PipedInputStream());
terminalConfiguration.setTerminal(createIOSafeTerminal());
initializeTerminal(terminalConfiguration);
}
private void initializeTerminalAndStreams() {
private IOSafeTerminal createIOSafeTerminal() {
return createRuntimeExceptionConvertingAdapter(createDefaultTerminal());
}
private Terminal createDefaultTerminal() {
try {
initalizeTerminalAndStreamsWithException();
return new DefaultTerminalFactory().createTerminal();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void initalizeTerminalAndStreamsWithException() throws IOException {
inputReader = new PipedInputStream();
inputWriter = new PipedOutputStream(inputReader);
outputReader = new PipedInputStream();
outputWriter = new PipedOutputStream(outputReader);
outputStream = new PrintStream(outputWriter);
safeOutputWriter = new SafeOutputStream(outputWriter);
lispTerminal = new LispTerminal(createIOSafeTerminal(), inputWriter, outputReader);
public LispMain(LispInterpreterBuilder builder, TerminalConfiguration configuration) {
this.builder = builder;
initializeTerminal(configuration);
}
private IOSafeTerminal createIOSafeTerminal() throws IOException {
Terminal defaultTerminal = new DefaultTerminalFactory().createTerminal();
private void initializeTerminal(TerminalConfiguration configuration) {
try {
initalizeTerminalWithException(configuration);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
return IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter(defaultTerminal);
private void initalizeTerminalWithException(TerminalConfiguration configuration) throws IOException {
PipedOutputStream inputWriter = configuration.getInputWriter();
PipedInputStream outputReader = configuration.getOutputReader();
inputReader = new PipedInputStream(inputWriter);
outputWriter = new PipedOutputStream(outputReader);
output = new PrintStream(outputWriter);
lispTerminal = new LispTerminal(configuration.getTerminal(), inputWriter, outputReader);
}
public void runInteractive() {
printGreeting();
lispTerminal.start();
buildInteractiveInterpreter().interpret();
shutdownTerminal();
}
private void printGreeting() {
outputStream.println(GREETING);
outputStream.println();
output.println(GREETING);
output.println();
}
private LispInterpreter buildInteractiveInterpreter() {
LispInterpreterBuilder builder = LispInterpreterBuilderImpl.getInstance();
builder.setInput(inputReader, "terminal");
builder.setOutput(outputStream);
builder.setErrorOutput(outputStream);
builder.setTerminationFunction(this::shutdown);
builder.setErrorTerminationFunction(this::shutdown);
builder.setOutput(output);
builder.setErrorOutput(output);
builder.setTerminationFunction(this::shutdownTerminal);
builder.setErrorTerminationFunction(this::shutdownTerminal);
builder.setPromptDecorator(s -> s + END_OF_SEGMENT);
builder.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN));
builder.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW));
@ -91,11 +109,10 @@ public class LispMain {
return builder.build();
}
private void shutdown() {
outputStream.println();
outputStream.println(END_OF_SEGMENT);
private void shutdownTerminal() {
output.print(END_OF_SEGMENT);
lispTerminal.stop();
safeOutputWriter.close();
output.close();
}
private Function<String, String> makeColorDecorator(String color) {
@ -108,12 +125,11 @@ public class LispMain {
};
}
private void runWithFile(String fileName) {
public void runWithFile(String fileName) {
buildFileInterpreter(fileName).interpret();
}
private LispInterpreter buildFileInterpreter(String fileName) {
LispInterpreterBuilder builder = LispInterpreterBuilderImpl.getInstance();
builder.useFile(fileName);
builder.setOutput(System.out);
builder.setErrorOutput(System.err);
@ -126,4 +142,36 @@ public class LispMain {
return builder.build();
}
public class TerminalConfiguration {
private PipedOutputStream inputWriter;
private PipedInputStream outputReader;
private IOSafeTerminal terminal;
public PipedOutputStream getInputWriter() {
return inputWriter;
}
public void setInputWriter(PipedOutputStream inputWriter) {
this.inputWriter = inputWriter;
}
public PipedInputStream getOutputReader() {
return outputReader;
}
public void setOutputReader(PipedInputStream outputReader) {
this.outputReader = outputReader;
}
public IOSafeTerminal getTerminal() {
return terminal;
}
public void setTerminal(IOSafeTerminal terminal) {
this.terminal = terminal;
}
}
}

View File

@ -1,7 +1,8 @@
package sexpression;
import static java.text.MessageFormat.format;
import java.math.BigInteger;
import java.text.MessageFormat;
import error.LispException;
@ -49,7 +50,7 @@ public class LispNumber extends Atom {
@Override
public String getMessage() {
return MessageFormat.format("{0} is not a valid integer", text);
return format("{0} is not a valid integer", text);
}
}

View File

@ -1,6 +1,7 @@
package table;
import java.text.MessageFormat;
import static java.text.MessageFormat.format;
import java.util.*;
import error.CriticalLispException;
@ -141,7 +142,7 @@ public class FunctionTable {
@Override
public String getMessage() {
return MessageFormat.format("Could not create an instance of ''{0}''", functionName);
return format("Could not create an instance of ''{0}''", functionName);
}
}

View File

@ -1,7 +1,6 @@
package terminal;
import static java.lang.Character.isDigit;
import static terminal.ControlSequenceLookup.lookupControlSequence;
import static util.Characters.*;
import stream.SafeInputStream;
@ -12,14 +11,13 @@ class ControlSequenceHandler {
return c == UNICODE_ESCAPE;
}
private ControlSequenceLookup controlSequenceLookup;
private SafeInputStream input;
private String code;
private int currentCharacter;
public ControlSequenceHandler() {
this.input = null;
this.code = "";
this.currentCharacter = 0;
this.controlSequenceLookup = new ControlSequenceLookup();
}
public ControlSequence parse(SafeInputStream inputStream) {
@ -30,7 +28,7 @@ class ControlSequenceHandler {
if (isExpectedFirstCharacter())
readCode();
return lookupControlSequence((char) currentCharacter, code);
return controlSequenceLookup.get((char) currentCharacter, code);
}
private void readCharacter() {

View File

@ -8,9 +8,15 @@ import terminal.ControlSequence.NullControlSequence;
public class ControlSequenceLookup {
private static Map<Character, Map<String, ControlSequence>> commands = new HashMap<>();
private Map<Character, Map<String, ControlSequence>> commands;
static {
public ControlSequenceLookup() {
this.commands = new HashMap<>();
initializeCommands();
}
private void initializeCommands() {
Map<String, ControlSequence> sgrCodes = new HashMap<>();
for (SelectGraphicRendition sgr : SelectGraphicRendition.values())
@ -19,7 +25,7 @@ public class ControlSequenceLookup {
commands.put(SGR_COMMAND, sgrCodes);
}
public static ControlSequence lookupControlSequence(char command, String code) {
public ControlSequence get(char command, String code) {
Map<String, ControlSequence> codes = commands.getOrDefault(command, new HashMap<>());
return codes.getOrDefault(code, new NullControlSequence());

View File

@ -115,13 +115,6 @@ public class LispTerminal {
return keyStroke;
}
private void doControlC() {
moveCursorToEndOfInput();
terminal.putCharacter('\n');
setOriginToCurrentPosition();
stop();
}
private synchronized void handleKey(KeyStroke keyStroke) {
doKey(keyStroke);
terminal.flush();
@ -142,10 +135,20 @@ public class LispTerminal {
}
private synchronized void doControlCharacter(KeyStroke keyStroke) {
if (keyStroke.getCharacter() == 'd')
if (keyStroke.getCharacter() == 'c')
doControlC();
else if (keyStroke.getCharacter() == 'd')
doControlD();
}
private void doControlC() {
moveCursorToEndOfInput();
terminal.putCharacter('\n');
inputLine = "";
setOriginToCurrentPosition();
stop();
}
private synchronized void doControlD() {
doEnter();
stop();
@ -374,7 +377,7 @@ public class LispTerminal {
}
private synchronized void putOutputToTerminal() {
SafeInputStream input = new SafeInputStream(new ByteArrayInputStream(outputSegment.getBytes()));
SafeInputStream input = convertOutputToStream();
for (int c = input.read(); c != EOF; c = input.read())
if (isEscape((char) c))
@ -383,6 +386,10 @@ public class LispTerminal {
terminal.putCharacter((char) c);
}
private synchronized SafeInputStream convertOutputToStream() {
return new SafeInputStream(new ByteArrayInputStream(outputSegment.getBytes()));
}
private void applyControlSequence(SafeInputStream input) {
ControlSequence controlSequence = controlSequenceHandler.parse(input);
controlSequence.applyTo(terminal);

View File

@ -1,6 +1,6 @@
package token;
import java.text.MessageFormat;
import static java.text.MessageFormat.format;
import error.*;
import file.FilePosition;
@ -37,7 +37,7 @@ public interface TokenFactory {
@Override
public String getMessagePrefix() {
return MessageFormat.format("illegal character >>{0}<<", text);
return format("illegal character >>{0}<<", text);
}
}

View File

@ -152,10 +152,9 @@ public class ErrorManagerTest {
}
@Test
public void severityCoverage() {
Severity.valueOf(WARNING.toString());
Severity.valueOf(ERROR.toString());
Severity.valueOf(CRITICAL.toString());
public void severityEnumCoverage() {
for (Severity severity : Severity.values())
Severity.valueOf(severity.toString());
}
}

View File

@ -1,10 +1,10 @@
package function.builtin;
import static java.text.MessageFormat.format;
import static org.junit.Assert.assertEquals;
import static testutil.TestUtilities.evaluateString;
import java.io.*;
import java.text.MessageFormat;
import org.junit.*;
@ -40,16 +40,16 @@ public class PRINTTest {
public void printStringWorks() {
String output = "\"Hello, world!\"";
evaluateString(MessageFormat.format("(print {0})", output));
assertPrinted(MessageFormat.format("{0}\n", output));
evaluateString(format("(print {0})", output));
assertPrinted(format("{0}\n", output));
}
@Test
public void printSymbolWorks() {
String output = "A";
evaluateString(MessageFormat.format("(print ''{0})", output));
assertPrinted(MessageFormat.format("{0}\n", output));
evaluateString(format("(print ''{0})", output));
assertPrinted(format("{0}\n", output));
}
@Test(expected = TooManyArgumentsException.class)

View File

@ -1,7 +1,10 @@
package interpreter;
import static error.ErrorManager.Severity.CRITICAL;
import static interpreter.InteractiveLispInterpreter.PROMPT;
import static java.text.MessageFormat.format;
import static org.junit.Assert.*;
import static testutil.TestUtilities.createInputStreamFromString;
import java.io.*;
import java.util.*;
@ -11,7 +14,7 @@ import org.junit.*;
import environment.RuntimeEnvironment;
import interpreter.LispInterpreterBuilderImpl.InterpreterAlreadyBuiltException;
public class LispInterpreterBuilderTest {
public class LispInterpreterTest {
private static final String TERMINATED = "terminated";
@ -21,7 +24,7 @@ public class LispInterpreterBuilderTest {
private RuntimeEnvironment environment;
private LispInterpreterBuilder builder;
public LispInterpreterBuilderTest() {
public LispInterpreterTest() {
this.environment = RuntimeEnvironment.getInstance();
this.builder = new LispInterpreterBuilderImpl() {
@ -68,6 +71,7 @@ public class LispInterpreterBuilderTest {
setCommonFeatures();
builder.setInput(System.in, "stdin");
LispInterpreter interpreter = builder.build();
assertTrue(interpreter instanceof InteractiveLispInterpreter);
}
@ -77,6 +81,7 @@ public class LispInterpreterBuilderTest {
builder.setInput(System.in, "stdin");
builder.setNotInteractive();
LispInterpreter interpreter = builder.build();
assertFalse(interpreter instanceof InteractiveLispInterpreter);
assertFalse(interpreter instanceof FileLispInterpreter);
}
@ -86,6 +91,7 @@ public class LispInterpreterBuilderTest {
setCommonFeatures();
builder.useFile("test/interpreter/test-files/file.lisp");
LispInterpreter interpreter = builder.build();
assertTrue(interpreter instanceof FileLispInterpreter);
}
@ -98,6 +104,7 @@ public class LispInterpreterBuilderTest {
@Test
public void interpreterAlreadyBuiltException_HasCorrectAttributes() {
InterpreterAlreadyBuiltException e = new InterpreterAlreadyBuiltException();
assertEquals(CRITICAL, e.getSeverity());
assertNotNull(e.getMessage());
assertTrue(e.getMessage().length() > 0);
@ -117,6 +124,7 @@ public class LispInterpreterBuilderTest {
setCommonFeatures();
builder.useFile("test/interpreter/test-files/does-not-exist.lisp");
builder.build();
assertErrorMessageWritten();
assertTerminated();
}
@ -124,6 +132,7 @@ public class LispInterpreterBuilderTest {
@Test
public void makeSureDecoratorsAreInitializedWithDefaults() {
builder.build();
assertEquals("", environment.decoratePrompt(""));
assertEquals("", environment.decorateValueOutput(""));
assertEquals("", environment.decorateWarningOutput(""));
@ -139,6 +148,7 @@ public class LispInterpreterBuilderTest {
builder.setErrorOutputDecorator(s -> "*" + s + "*");
builder.setCriticalOutputDecorator(s -> "$" + s + "$");
builder.build();
assertEquals("#x#", environment.decoratePrompt("x"));
assertEquals("@x@", environment.decorateValueOutput("x"));
assertEquals("%x%", environment.decorateWarningOutput("x"));
@ -146,4 +156,35 @@ public class LispInterpreterBuilderTest {
assertEquals("$x$", environment.decorateCriticalOutput("x"));
}
@Test
public void fileBasedInterpreterWorks() {
setCommonFeatures();
builder.useFile("test/interpreter/test-files/file.lisp");
builder.build().interpret();
assertEquals("PICKLE\n\n", outputStream.toString());
assertEquals("", errorOutputStream.toString());
}
@Test
public void interactiveInterpreterWorks() {
setCommonFeatures();
builder.setInput(createInputStreamFromString("'pickle"), "input");
builder.build().interpret();
assertEquals(format("{0}\n{1}\n{0}\n\n", PROMPT, "PICKLE"), outputStream.toString());
assertEquals("", errorOutputStream.toString());
}
@Test
public void interpreterHandlesError() {
setCommonFeatures();
builder.setNotInteractive();
builder.setInput(createInputStreamFromString("pickle"), "input");
builder.build().interpret();
assertEquals("\n", outputStream.toString());
assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream.toString());
}
}

View File

@ -0,0 +1 @@
'pickle

View File

@ -0,0 +1,43 @@
package stream;
import static org.junit.Assert.assertEquals;
import static testutil.TestUtilities.*;
import org.junit.*;
public class SafeInputStreamTest {
SafeInputStream safe;
SafeInputStream safeWithException;
@Before
public void setUp() throws Exception {
safe = new SafeInputStream(createInputStreamFromString("a"));
safeWithException = new SafeInputStream(createIOExceptionThrowingInputStream());
}
@After
public void tearDown() throws Exception {}
@Test
public void readWorks() {
assertEquals('a', (char) safe.read());
assertEquals(-1, safe.read());
}
@Test
public void closeWorks() {
safe.close();
}
@Test(expected = UncheckedIOException.class)
public void readThrowsUncheckedException() {
safeWithException.read();
}
@Test(expected = UncheckedIOException.class)
public void closeThrowsUncheckedException() {
safeWithException.close();
}
}

View File

@ -0,0 +1,54 @@
package stream;
import static org.junit.Assert.assertEquals;
import static testutil.TestUtilities.createIOExceptionThrowingOutputStream;
import java.io.ByteArrayOutputStream;
import org.junit.*;
public class SafeOutputStreamTest {
SafeOutputStream safe;
SafeOutputStream safeWithException;
ByteArrayOutputStream output;
@Before
public void setUp() throws Exception {
output = new ByteArrayOutputStream();
safe = new SafeOutputStream(output);
safeWithException = new SafeOutputStream(createIOExceptionThrowingOutputStream());
}
@Test
public void writeWorks() {
safe.write("write".getBytes());
assertEquals("write", output.toString());
}
@Test
public void flushWorks() {
safe.flush();
}
@Test
public void closeWorks() {
safe.close();
}
@Test(expected = UncheckedIOException.class)
public void writeThrowsUncheckedException() {
safeWithException.write("write".getBytes());
}
@Test(expected = UncheckedIOException.class)
public void flushThrowsUncheckedException() {
safeWithException.flush();
}
@Test(expected = UncheckedIOException.class)
public void closeThrowsUncheckedException() {
safeWithException.close();
}
}

View File

@ -1,6 +1,6 @@
package terminal;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static terminal.SelectGraphicRendition.*;
import java.util.*;
@ -79,4 +79,16 @@ public class ControlSequenceTest {
assertTrue(indicatorSet.contains("MAGENTA"));
}
@Test
public void nullControlSequenceHasCorrectCode() {
ControlSequence nullControlSequence = new NullControlSequence();
assertEquals("", nullControlSequence.getCode());
}
@Test
public void SelectGraphicRenditionEnumCoverage() {
for (SelectGraphicRendition sgr : SelectGraphicRendition.values())
SelectGraphicRendition.valueOf(sgr.toString());
}
}

View File

@ -347,6 +347,17 @@ public class LispTerminalTest {
assertInputWritten("control-d\n");
}
@Test
public void controlCWorks() {
enterCharacters("ctrl-c");
enterControlCharacter('c');
produceOutput("");
assertInputStreamClosed();
assertInputWritten("");
assertCharacterPositions(new char[][] { { 'c', 't', 'r', 'l', '-', 'c', ' ', ' ', ' ' },
{ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } });
}
@Test
public void controlDWorksInMiddleOfInput() {
enterCharacters("control-d");

View File

@ -23,7 +23,37 @@ public final class TestUtilities {
@Override
public int read() throws IOException {
throw new IOException("test IOException");
throw new IOException("read()");
}
@Override
public void close() throws IOException {
throw new IOException("close()");
}
};
}
public static OutputStream createIOExceptionThrowingOutputStream() {
return new OutputStream() {
@Override
public void write(byte[] b) throws IOException {
throw new IOException("write(byte[])");
}
@Override
public void flush() throws IOException {
throw new IOException("flush()");
}
@Override
public void close() throws IOException {
throw new IOException("close()");
}
@Override
public void write(int arg0) throws IOException {
throw new IOException("write(int)");
}
};
}