Added an argument validator and unit tests
This commit is contained in:
parent
5f2c3dc469
commit
fbd2b3207c
|
@ -13,11 +13,6 @@ public abstract class LineColumnException extends LispException {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSeverity() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return MessageFormat.format("{0} - line {1}, column {2}", getMessagePrefix(), position.getLineNumber(),
|
return MessageFormat.format("{0} - line {1}, column {2}", getMessagePrefix(), position.getLineNumber(),
|
||||||
|
|
|
@ -4,6 +4,8 @@ public abstract class LispException extends RuntimeException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public abstract int getSeverity();
|
public int getSeverity() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package eval.argument;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import error.LispException;
|
||||||
|
import eval.LENGTH;
|
||||||
|
import sexpression.*;
|
||||||
|
|
||||||
|
public class ArgumentValidator {
|
||||||
|
|
||||||
|
private Class<? extends SExpression> argumentType;
|
||||||
|
private String functionName;
|
||||||
|
private Integer maximumNumberOfArguments;
|
||||||
|
private Integer minimumNumberOfArguments;
|
||||||
|
|
||||||
|
public ArgumentValidator(String functionName) {
|
||||||
|
this.argumentType = SExpression.class;
|
||||||
|
this.functionName = functionName;
|
||||||
|
this.minimumNumberOfArguments = null;
|
||||||
|
this.maximumNumberOfArguments = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArgumentType(Class<? extends SExpression> argumentType) {
|
||||||
|
this.argumentType = argumentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaximumNumberOfArguments(int maximumNumberOfArguments) {
|
||||||
|
this.maximumNumberOfArguments = maximumNumberOfArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinimumNumberOfArguments(int minimumNumberOfArguments) {
|
||||||
|
this.minimumNumberOfArguments = minimumNumberOfArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExactNumberOfArguments(int exactNumberOfArguments) {
|
||||||
|
this.minimumNumberOfArguments = exactNumberOfArguments;
|
||||||
|
this.maximumNumberOfArguments = exactNumberOfArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(Cons argumentList) {
|
||||||
|
if (containsTooFewArguments(argumentList))
|
||||||
|
throw new TooFewArgumentsException(functionName, argumentList);
|
||||||
|
else if (containsTooManyArguments(argumentList))
|
||||||
|
throw new TooManyArgumentsException(functionName, argumentList);
|
||||||
|
else if (!isExpectedArgumentType(argumentList.getCar()))
|
||||||
|
throw new BadArgumentTypeException(functionName, argumentList.getCar());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsTooFewArguments(Cons argumentList) {
|
||||||
|
return (minimumNumberOfArguments != null) && (LENGTH.getLength(argumentList) < minimumNumberOfArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsTooManyArguments(Cons argumentList) {
|
||||||
|
return (maximumNumberOfArguments != null) && (LENGTH.getLength(argumentList) > maximumNumberOfArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExpectedArgumentType(SExpression firstArgument) {
|
||||||
|
return argumentType.isInstance(firstArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TooFewArgumentsException extends LispException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String functionName;
|
||||||
|
private Cons originalSExpression;
|
||||||
|
|
||||||
|
public TooFewArgumentsException(String functionName, Cons argumentList) {
|
||||||
|
this.functionName = functionName;
|
||||||
|
this.originalSExpression = new Cons(new Symbol(this.functionName), argumentList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return MessageFormat.format("too few arguments given to {0}: {1}", functionName, originalSExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TooManyArgumentsException extends LispException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String functionName;
|
||||||
|
private Cons originalSExpression;
|
||||||
|
|
||||||
|
public TooManyArgumentsException(String functionName, Cons argumentList) {
|
||||||
|
this.functionName = functionName;
|
||||||
|
this.originalSExpression = new Cons(new Symbol(this.functionName), argumentList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return MessageFormat.format("too many arguments given to {0}: {1}", functionName, originalSExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BadArgumentTypeException extends LispException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String functionName;
|
||||||
|
private String argument;
|
||||||
|
|
||||||
|
public BadArgumentTypeException(String functionName, SExpression argument) {
|
||||||
|
this.functionName = functionName;
|
||||||
|
this.argument = argument.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return MessageFormat.format("{0}: {1} is not the expected type", functionName, argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ public class InteractiveLispInterpreter extends LispInterpreter {
|
||||||
private static final String GREETING = "SUNY Potsdam Lisp Interpreter - Version 4.4.3";
|
private static final String GREETING = "SUNY Potsdam Lisp Interpreter - Version 4.4.3";
|
||||||
private static final String PROMPT = "~ ";
|
private static final String PROMPT = "~ ";
|
||||||
|
|
||||||
public InteractiveLispInterpreter(InputStream inputStream, ErrorManager errorManager, PrintStream outputStream) {
|
public InteractiveLispInterpreter(InputStream inputStream, PrintStream outputStream, ErrorManager errorManager) {
|
||||||
super(inputStream, errorManager, outputStream);
|
super(inputStream, outputStream, errorManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void printGreeting() {
|
protected void printGreeting() {
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class LispInterpreter {
|
||||||
private ErrorManager errorManager;
|
private ErrorManager errorManager;
|
||||||
protected PrintStream outputStream;
|
protected PrintStream outputStream;
|
||||||
|
|
||||||
public LispInterpreter(InputStream inputStream, ErrorManager errorManager, PrintStream outputStream) {
|
public LispInterpreter(InputStream inputStream, PrintStream outputStream, ErrorManager errorManager) {
|
||||||
this.errorManager = errorManager;
|
this.errorManager = errorManager;
|
||||||
this.parser = new LispParser(inputStream, inputStream.toString());
|
this.parser = new LispParser(inputStream, inputStream.toString());
|
||||||
this.outputStream = outputStream;
|
this.outputStream = outputStream;
|
||||||
|
@ -63,11 +63,6 @@ public class LispInterpreter {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSeverity() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return e.getMessage();
|
return e.getMessage();
|
||||||
|
|
|
@ -11,30 +11,22 @@ public class LispMain {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
LispInterpreter interpreter = null;
|
LispInterpreter interpreter = null;
|
||||||
ErrorManager errorManager = new ErrorManager(new TerminateInterpreter(), System.err::print);
|
ErrorManager errorManager = new ErrorManager(() -> System.exit(1), System.err::print);
|
||||||
|
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
String fileName = args[0];
|
String fileName = args[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
interpreter = new LispInterpreter(new FileInputStream(fileName), errorManager, System.out);
|
interpreter = new LispInterpreter(new FileInputStream(fileName), System.out, errorManager);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
errorManager.generateError(new LispFileNotFoundException(e));
|
errorManager.generateError(new LispFileNotFoundException(e));
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
interpreter = new InteractiveLispInterpreter(System.in, errorManager, System.out);
|
interpreter = new InteractiveLispInterpreter(System.in, System.out, errorManager);
|
||||||
|
|
||||||
interpreter.interpret();
|
interpreter.interpret();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TerminateInterpreter implements Runnable {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LispFileNotFoundException extends LispException {
|
public static class LispFileNotFoundException extends LispException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
|
@ -41,11 +41,6 @@ public class LispNumber extends Atom {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSeverity() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return MessageFormat.format("{0} is not a valid integer", text);
|
return MessageFormat.format("{0} is not a valid integer", text);
|
||||||
|
|
|
@ -5,7 +5,6 @@ import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -18,23 +17,7 @@ public class ErrorManagerTester {
|
||||||
private Set<String> indicatorSet;
|
private Set<String> indicatorSet;
|
||||||
|
|
||||||
private ErrorManager createErrorManagerWithIndicators() {
|
private ErrorManager createErrorManagerWithIndicators() {
|
||||||
Runnable terminationFunction = new Runnable() {
|
return new ErrorManager(() -> indicatorSet.add(TERMINATED), (String) -> indicatorSet.add(MESSAGE));
|
||||||
|
|
||||||
@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) {
|
private LispException createLispException(int severity) {
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package eval.argument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
import error.ErrorManager;
|
||||||
|
import eval.argument.ArgumentValidator.*;
|
||||||
|
import sexpression.*;
|
||||||
|
|
||||||
|
public class ArgumentValidatorTester {
|
||||||
|
|
||||||
|
private ArgumentValidator validator;
|
||||||
|
|
||||||
|
private Cons makeArgumentListOfSize(int size) {
|
||||||
|
Cons argumentList = Nil.getUniqueInstance();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
argumentList = new Cons(Nil.getUniqueInstance(), argumentList);
|
||||||
|
|
||||||
|
return argumentList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
validator = new ArgumentValidator("TEST");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noConstraints_DoesNotThrowExceptionWithNoArguments() {
|
||||||
|
validator.validate(makeArgumentListOfSize(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noConstraints_DoesNotThrowExceptionWithOneArgument() {
|
||||||
|
validator.validate(makeArgumentListOfSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noConstraints_DoesNotThrowExceptionWithManyArguments() {
|
||||||
|
validator.validate(makeArgumentListOfSize(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = TooFewArgumentsException.class)
|
||||||
|
public void tooFewArgumentsWithMinimumSet_ThrowsException() {
|
||||||
|
validator.setMinimumNumberOfArguments(1);
|
||||||
|
validator.validate(makeArgumentListOfSize(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = TooManyArgumentsException.class)
|
||||||
|
public void tooManyArgumentsWithMaximumSet_ThrowsException() {
|
||||||
|
validator.setMaximumNumberOfArguments(1);
|
||||||
|
validator.validate(makeArgumentListOfSize(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exactNumberOfArguments_DoesNotThrowException() {
|
||||||
|
validator.setExactNumberOfArguments(5);
|
||||||
|
validator.validate(makeArgumentListOfSize(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = TooFewArgumentsException.class)
|
||||||
|
public void tooFewArgumentsWithExactSet_ThrowsException() {
|
||||||
|
validator.setExactNumberOfArguments(3);
|
||||||
|
validator.validate(makeArgumentListOfSize(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = TooManyArgumentsException.class)
|
||||||
|
public void tooManyArgumentsWithExactSet_ThrowsException() {
|
||||||
|
validator.setExactNumberOfArguments(3);
|
||||||
|
validator.validate(makeArgumentListOfSize(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tooManyArgumentsException_HasCorrectSeverity() {
|
||||||
|
TooManyArgumentsException e = new TooManyArgumentsException("TEST", Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tooManyArgumentsException_HasMessageText() {
|
||||||
|
TooManyArgumentsException e = new TooManyArgumentsException("TEST", Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertNotNull(e.getMessage());
|
||||||
|
assertTrue(e.getMessage().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tooFewArgumentsException_HasCorrectSeverity() {
|
||||||
|
TooFewArgumentsException e = new TooFewArgumentsException("TEST", Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tooFewArgumentsException_HasMessageText() {
|
||||||
|
TooFewArgumentsException e = new TooFewArgumentsException("TEST", Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertNotNull(e.getMessage());
|
||||||
|
assertTrue(e.getMessage().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void BadArgumentTypeException_HasCorrectSeverity() {
|
||||||
|
BadArgumentTypeException e = new BadArgumentTypeException("TEST", Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void BadArgumentTypeException_HasMessageText() {
|
||||||
|
BadArgumentTypeException e = new BadArgumentTypeException("TEST", Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertNotNull(e.getMessage());
|
||||||
|
assertTrue(e.getMessage().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void correctArgumentType_DoesNotThrowException() {
|
||||||
|
validator.setArgumentType(Nil.class);
|
||||||
|
validator.validate(makeArgumentListOfSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BadArgumentTypeException.class)
|
||||||
|
public void badArgumentType_ThrowsException() {
|
||||||
|
validator.setArgumentType(LispString.class);
|
||||||
|
validator.validate(makeArgumentListOfSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue