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; package error;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.function.Consumer;
/** /**
* Prints error messages and potentially terminates the application. * 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_YELLOW = "\u001B[33m";
public static final String ANSI_PURPLE = "\u001B[35m"; 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 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); ANSI_RESET);
System.out.println(formattedMessage); outputFunction.accept(formattedMessage);
if (lispException.getSeverity() >= CRITICAL_LEVEL) { 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 * 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 * should override this method to return false if it does not want its arguments to be evaluated
* be evaluated prior to being passed. * prior to being passed.
*
* @return <code>true</code>
*/ */
public boolean evaluateArguments() { public boolean evaluateArguments() {
return true; return true;

View File

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