Added unit tests for exit and symbol-function and refactored some code

This commit is contained in:
Mike Cifelli 2017-01-22 11:11:16 -05:00
parent ea8acd423f
commit 1f0d312e7e
3 changed files with 142 additions and 45 deletions

View File

@ -1,61 +1,50 @@
package function.builtin; package function.builtin;
import java.text.MessageFormat;
import error.LispException;
import function.*; import function.*;
import function.builtin.cons.LENGTH;
import sexpression.*; import sexpression.*;
/**
* <code>SYMBOL_FUNCTION</code> represents the SYMBOL-FUNCTION function in
* Lisp.
*/
public class SYMBOL_FUNCTION extends LispFunction { public class SYMBOL_FUNCTION extends LispFunction {
// The number of arguments that SYMBOL-FUNCTION takes. private ArgumentValidator argumentValidator;
private static final int NUM_ARGS = 1;
public SExpression call(Cons argList) { public SYMBOL_FUNCTION() {
// retrieve the number of arguments passed to SYMBOL-FUNCTION this.argumentValidator = new ArgumentValidator("SYMBOL-FUNCTION");
int argListLength = LENGTH.getLength(argList); this.argumentValidator.setExactNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(Symbol.class);
}
// make sure we have received the proper number of arguments public SExpression call(Cons argumentList) {
if (argListLength != NUM_ARGS) { argumentValidator.validate(argumentList);
Cons originalSExpr = new Cons(new Symbol("SYMBOL-FUNCTION"),
argList);
String errMsg = "too " +
((argListLength > NUM_ARGS) ? "many" : "few") +
" arguments given to SYMBOL-FUNCTION: " +
originalSExpr;
throw new RuntimeException(errMsg); SExpression symbol = argumentList.getCar();
LispFunction function = EVAL.lookupFunction(symbol.toString());
if (function != null) {
if (function instanceof UserDefinedFunction)
return ((UserDefinedFunction) function).getLambdaExpression();
return new Symbol(MessageFormat.format("#<SYSTEM-FUNCTION {0}>", symbol.toString()));
} }
SExpression arg = argList.getCar(); throw new UndefinedSymbolFunctionException(symbol);
}
// make sure the argument is a symbol public static class UndefinedSymbolFunctionException extends LispException {
if (arg.symbolp()) {
LispFunction function = EVAL.lookupFunction(arg.toString());
// make sure the function actually exists private static final long serialVersionUID = 1L;
if (function != null) { private SExpression function;
if (function instanceof UserDefinedFunction) {
// this is a user-defined function
UserDefinedFunction udFunction = (UserDefinedFunction) function; public UndefinedSymbolFunctionException(SExpression function) {
this.function = function;
return udFunction.getLambdaExpression();
}
// this is a built-in function
return new Symbol("SUBR-" + arg.toString());
}
throw new RuntimeException("SYMBOL-FUNCTION: undefined function " +
arg);
} }
throw new RuntimeException("SYMBOL-FUNCTION: " + arg + @Override
" is not a symbol"); public String getMessage() {
return MessageFormat.format("SYMBOL-FUNCTION: undefined function: {0}", function);
}
} }
} }

View File

@ -0,0 +1,48 @@
package function.builtin;
import static org.junit.Assert.*;
import static testutil.TestUtilities.evaluateString;
import java.util.*;
import org.junit.*;
import environment.Environment;
import function.ArgumentValidator.TooManyArgumentsException;
public class EXITTester {
private static final String TERMINATED = "terminated";
private Set<String> indicatorSet;
private void assertTerminated() {
assertTrue(indicatorSet.contains(TERMINATED));
}
private void assertNotTerminated() {
assertFalse(indicatorSet.contains(TERMINATED));
}
@Before
public void setUp() {
indicatorSet = new HashSet<>();
Environment.getInstance().setTerminationFunction(() -> indicatorSet.add(TERMINATED));
}
@Test
public void exitWorks() {
evaluateString("(exit)");
assertTerminated();
}
@Test
public void exitNotCalled_IndicatorSetIsClean() {
assertNotTerminated();
}
@Test(expected = TooManyArgumentsException.class)
public void testExitWithTooManyArguments() {
evaluateString("(exit 1)");
}
}

View File

@ -0,0 +1,60 @@
package function.builtin;
import static org.junit.Assert.*;
import static testutil.TestUtilities.evaluateString;
import org.junit.Test;
import function.ArgumentValidator.*;
import function.builtin.SYMBOL_FUNCTION.UndefinedSymbolFunctionException;
import sexpression.Nil;
public class SYMBOL_FUNCTIONTester {
@Test
public void testSymbolFunction_BuiltinFunction() {
String input = "(symbol-function '+)";
assertEquals("#<SYSTEM-FUNCTION +>", evaluateString(input).toString());
}
@Test
public void testSymbolFunction_UserDefinedFunction() {
String defineUserFunction = "(defun y (n m) (+ n m))";
String input = "(symbol-function 'y)";
evaluateString(defineUserFunction);
assertEquals("(Y (N M) (+ N M))", evaluateString(input).toString());
}
@Test(expected = RuntimeException.class)
public void testSymbolFunction_NonFunction() {
String input = "(symbol-function 'a)";
evaluateString(input);
}
@Test(expected = BadArgumentTypeException.class)
public void testSymbolFunctionWithBadArgumentType() {
evaluateString("(symbol-function 2)");
}
@Test(expected = TooManyArgumentsException.class)
public void testSymbolFunctionWithTooManyArguments() {
evaluateString("(symbol-function 'a 'b)");
}
@Test(expected = TooFewArgumentsException.class)
public void testSymbolFunctionWithTooFewArguments() {
evaluateString("(symbol-function)");
}
@Test
public void undefinedSymbolFunctionException_HasMessageText() {
UndefinedSymbolFunctionException e = new UndefinedSymbolFunctionException(Nil.getInstance());
assertNotNull(e.getMessage());
assertTrue(e.getMessage().length() > 0);
}
}