Refactored the ErrorManager and added unit tests

This commit is contained in:
Mike Cifelli 2016-12-16 12:31:16 -05:00
parent 60a7eb562c
commit 25c0b5813b
4 changed files with 135 additions and 17 deletions

View File

@ -1,6 +1,7 @@
package error;
import java.text.MessageFormat;
import java.util.function.Consumer;
/**
* Prints error messages and potentially terminates the application.
@ -14,15 +15,23 @@ public class ErrorManager {
public static final String ANSI_YELLOW = "\u001B[33m";
public static final String ANSI_PURPLE = "\u001B[35m";
public static void generateError(LispException lispException) {
private Runnable systemTerminatingFunction;
private Consumer<String> outputFunction;
public ErrorManager(Runnable systemTerminatingFunction, Consumer<String> outputFunction) {
this.systemTerminatingFunction = systemTerminatingFunction;
this.outputFunction = outputFunction;
}
public void generateError(LispException lispException) {
String color = (lispException.getSeverity() >= CRITICAL_LEVEL) ? ANSI_PURPLE : ANSI_RED;
String formattedMessage = MessageFormat.format("{0}error: {1}{2}", color, lispException.getMessage(),
String formattedMessage = MessageFormat.format("{0}error: {1}{2}\n", color, lispException.getMessage(),
ANSI_RESET);
System.out.println(formattedMessage);
outputFunction.accept(formattedMessage);
if (lispException.getSeverity() >= CRITICAL_LEVEL) {
System.exit(1);
systemTerminatingFunction.run();
}
}

View File

@ -23,10 +23,8 @@ public abstract class LispFunction {
/**
* Determine if the arguments passed to this Lisp function should be evaluated. A subclass
* should override this method to return <code>false</code> if it does not want its arguments to
* be evaluated prior to being passed.
*
* @return <code>true</code>
* should override this method to return false if it does not want its arguments to be evaluated
* prior to being passed.
*/
public boolean evaluateArguments() {
return true;

View File

@ -6,14 +6,15 @@
package main;
import parser.*;
import sexpression.SExpression;
import eval.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.MessageFormat;
import error.ErrorManager;
import error.LispException;
import java.io.*;
import java.text.MessageFormat;
import eval.EVAL;
import parser.LispParser;
import sexpression.SExpression;
/**
* This is an interpreter for the Lisp programming language. It takes the name of a file as a
@ -36,6 +37,7 @@ public class LispInterpreter {
*/
public static void main(String[] args) {
LispParser parser = null;
ErrorManager errorManager = new ErrorManager(new TerminateInterpreter(), System.out::print);
boolean interactive = false;
if (args.length > 0) {
@ -44,7 +46,7 @@ public class LispInterpreter {
try {
parser = new LispParser(new FileInputStream(args[0]), args[0]);
} catch (FileNotFoundException e) {
ErrorManager.generateError(new LispException() {
errorManager.generateError(new LispException() {
private static final long serialVersionUID = 1L;
@ -78,10 +80,10 @@ public class LispInterpreter {
System.out.println(result);
} catch (LispException e) {
LispInterpreter.erasePrompt(interactive);
ErrorManager.generateError(e);
errorManager.generateError(e);
} catch (RuntimeException e) {
LispInterpreter.erasePrompt(interactive);
ErrorManager.generateError(new LispException() {
errorManager.generateError(new LispException() {
private static final long serialVersionUID = 1L;
@ -113,4 +115,12 @@ public class LispInterpreter {
}
}
private static class TerminateInterpreter implements Runnable {
@Override
public void run() {
System.exit(1);
}
}
}

View File

@ -0,0 +1,101 @@
package error;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import org.junit.Test;
public class ErrorManagerTester {
private static final String TERMINATED = "terminated";
private static final String MESSAGE = "message";
private ErrorManager createErrorManagerWithIndicators(Set<String> indicatorSet) {
Runnable terminationFunction = new Runnable() {
@Override
public void run() {
indicatorSet.add(TERMINATED);
}
};
Consumer<String> outputFunction = new Consumer<String>() {
@Override
public void accept(String t) {
indicatorSet.add(MESSAGE);
}
};
return new ErrorManager(terminationFunction, outputFunction);
}
private LispException createLispException(int severity) {
return new LispException() {
private static final long serialVersionUID = 1L;
@Override
public int getSeverity() {
return severity;
}
@Override
public String getMessage() {
return MESSAGE;
}
};
}
@Test
public void givenCriticalExceptionSeverity_RunsProvidedTerminationFunction() {
Set<String> indicatorSet = new HashSet<>();
ErrorManager errorManager = createErrorManagerWithIndicators(indicatorSet);
errorManager.generateError(createLispException(ErrorManager.CRITICAL_LEVEL));
assertTrue(indicatorSet.contains(TERMINATED));
}
@Test
public void givenNonCriticalExceptionSeverity_DoesNotRunProvidedTerminationFunction() {
Set<String> indicatorSet = new HashSet<>();
ErrorManager errorManager = createErrorManagerWithIndicators(indicatorSet);
errorManager.generateError(createLispException(0));
assertFalse(indicatorSet.contains(TERMINATED));
}
@Test
public void noMessageDisplayedBeforeError() {
Set<String> indicatorSet = new HashSet<>();
createErrorManagerWithIndicators(indicatorSet);
assertFalse(indicatorSet.contains(TERMINATED));
assertFalse(indicatorSet.contains(MESSAGE));
}
@Test
public void usesOutputFunctionToDisplayMessages_NoTermination() {
Set<String> indicatorSet = new HashSet<>();
ErrorManager errorManager = createErrorManagerWithIndicators(indicatorSet);
errorManager.generateError(createLispException(0));
assertFalse(indicatorSet.contains(TERMINATED));
assertTrue(indicatorSet.contains(MESSAGE));
}
@Test
public void usesOutputFunctionToDisplayMessages_WithTermination() {
Set<String> indicatorSet = new HashSet<>();
ErrorManager errorManager = createErrorManagerWithIndicators(indicatorSet);
errorManager.generateError(createLispException(ErrorManager.CRITICAL_LEVEL));
assertTrue(indicatorSet.contains(TERMINATED));
assertTrue(indicatorSet.contains(MESSAGE));
}
}