Added unit tests and did some refactoring

This commit is contained in:
Mike Cifelli 2016-12-20 12:03:37 -05:00
parent 621ab9f2cb
commit c4531b25e2
4 changed files with 109 additions and 43 deletions

View File

@ -8,65 +8,47 @@ import table.SymbolTable;
public class UserDefinedFunction extends LispFunction {
// the number of arguments that this user-defined function takes.
private final int NUM_ARGS;
private ArgumentValidator argumentValidator;
private String name;
private Cons body;
private Cons lexpr;
private Cons lambdaExpression;
private SymbolTable environment;
private ArrayList<String> parameters;
private ArrayList<String> formalParameters;
/**
* Create a new user-defined function with the specified name, lambda list
* and body.
* Create a new user-defined function with the specified name, lambda list and body.
*
* @param name
* the name of this user-defined function
* the name of this user-defined function
* @param lambdaList
* a list of the formal parameters of this user-defined function (MUST BE
* A PROPER LIST)
* a list of the formal parameters of this user-defined function (MUST BE A PROPER
* LIST)
* @param body
* the body of this user-defined function (MUST BE A PROPER LIST)
* the body of this user-defined function (MUST BE A PROPER LIST)
*/
public UserDefinedFunction(String name, Cons lambdaList, Cons body) {
this.name = name;
this.body = body;
this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));
this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body));
this.environment = SETF.getEnvironment();
this.parameters = new ArrayList<String>();
this.formalParameters = new ArrayList<String>();
// retrieve the names of all the formal parameters of this function
while (lambdaList.consp()) {
this.parameters.add(lambdaList.getCar().toString());
for (; lambdaList.consp(); lambdaList = (Cons) lambdaList.getCdr())
this.formalParameters.add(lambdaList.getCar().toString());
lambdaList = (Cons) lambdaList.getCdr();
}
this.NUM_ARGS = this.parameters.size();
this.argumentValidator = new ArgumentValidator(this.name);
this.argumentValidator.setExactNumberOfArguments(this.formalParameters.size());
}
public SExpression call(Cons argList) {
// retrieve the number of arguments passed to this function
int argListLength = LENGTH.getLength(argList);
// make sure we have received the proper number of arguments
if (argListLength != NUM_ARGS) {
Cons originalSExpr = new Cons(new Symbol(name), argList);
String errMsg = "too " +
((argListLength > NUM_ARGS) ? "many" : "few") +
" arguments given to " + name + ": " +
originalSExpr;
throw new RuntimeException(errMsg);
}
argumentValidator.validate(argList);
// push a new symbol table onto this function's environment (for its
// parameters)
environment = new SymbolTable(environment);
// bind the values of the arguments to the formal parameter names
for (String param : parameters) {
for (String param : formalParameters) {
SExpression currentArg = argList.getCar();
environment.put(param, currentArg);
@ -102,14 +84,8 @@ public class UserDefinedFunction extends LispFunction {
return retval;
}
/**
* Return the lambda expression that represents this user-defined function.
*
* @return
* the lambda expression that represents this user-defined function
*/
public Cons getLexpr() {
return lexpr;
public Cons getLambdaExpression() {
return lambdaExpression;
}
}

View File

@ -41,7 +41,7 @@ public class SYMBOL_FUNCTION extends LispFunction {
UserDefinedFunction udFunction = (UserDefinedFunction) function;
return udFunction.getLexpr();
return udFunction.getLambdaExpression();
}
// this is a built-in function

View File

@ -0,0 +1,24 @@
package function;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import sexpression.*;
public class LispFunctionTester {
@Test
public void testEvaluateArguments() {
LispFunction lispFunction = new LispFunction() {
@Override
public SExpression call(Cons argList) {
return null;
}
};
assertTrue(lispFunction.evaluateArguments());
}
}

View File

@ -0,0 +1,66 @@
package function;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import function.ArgumentValidator.*;
import sexpression.*;
public class UserDefinedFunctionTester {
private static final String FUNCTION_NAME = "TEST";
private UserDefinedFunction createNoArgumentFunctionThatReturnsNil() {
return new UserDefinedFunction(FUNCTION_NAME, Nil.getUniqueInstance(),
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance()));
}
private UserDefinedFunction createOneArgumentFunctionThatReturnsArgument() {
return new UserDefinedFunction(FUNCTION_NAME, new Cons(new Symbol("X"), Nil.getUniqueInstance()),
new Cons(new Symbol("X"), Nil.getUniqueInstance()));
}
@Test
public void testNilFunctionCall() {
UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil();
assertEquals(Nil.getUniqueInstance(), function.call(Nil.getUniqueInstance()));
}
@Test
public void testNilFunctionToString() {
UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil();
Cons expected = new Cons(new Symbol(FUNCTION_NAME),
new Cons(Nil.getUniqueInstance(),
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())));
assertEquals(expected.toString(), function.getLambdaExpression().toString());
}
@Test
public void oneArgumentFunction_ReturnsCorrectValue() {
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
SExpression argument = new LispNumber(23);
Cons argumentList = new Cons(argument, Nil.getUniqueInstance());
assertEquals(argument.toString(), function.call(argumentList).toString());
}
@Test(expected = TooManyArgumentsException.class)
public void oneArgumentFunction_ThrowsExceptionWithTooManyArguments() {
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
SExpression argument = new LispNumber(23);
Cons argumentList = new Cons(argument, new Cons(argument, Nil.getUniqueInstance()));
function.call(argumentList);
}
@Test(expected = TooFewArgumentsException.class)
public void oneArgumentFunction_ThrowsExceptionWithTooFewArguments() {
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
function.call(Nil.getUniqueInstance());
}
}