Added unit tests and refactored the equal function

This commit is contained in:
Mike Cifelli 2016-12-30 10:22:25 -05:00
parent d0da7813bd
commit 9f80fc9abe
2 changed files with 88 additions and 47 deletions

View File

@ -1,48 +1,66 @@
package function.builtin;
import function.LispFunction;
import function.*;
import sexpression.*;
/**
* <code>EQUAL</code> represents the EQUAL function in Lisp.
*/
public class EQUAL extends LispFunction {
// The number of arguments that EQUAL takes.
private static final int NUM_ARGS = 2;
private ArgumentValidator argumentValidator;
public SExpression call(Cons argList) {
// retrieve the number of arguments passed to EQUAL
int argListLength = LENGTH.getLength(argList);
public EQUAL() {
this.argumentValidator = new ArgumentValidator("EQUAL");
this.argumentValidator.setExactNumberOfArguments(2);
}
// make sure we have received the proper number of arguments
if (argListLength != NUM_ARGS) {
Cons originalSExpr = new Cons(new Symbol("EQUAL"), argList);
String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to EQUAL: "
+ originalSExpr;
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
throw new RuntimeException(errMsg);
}
return callRecursive(argumentList);
}
SExpression argOne = argList.getCar(); // first argument
Cons cdr = (Cons) argList.getCdr();
SExpression argTwo = cdr.getCar(); // second argumnet
private SExpression callRecursive(Cons argumentList) {
Cons cdr = (Cons) argumentList.getCdr();
SExpression firstArgument = argumentList.getCar();
SExpression secondArgument = cdr.getCar();
if (argOne.consp() && argTwo.consp()) {
Cons listOne = (Cons) argOne;
Cons listTwo = (Cons) argTwo;
SExpression listOneCar = listOne.getCar();
SExpression listTwoCar = listTwo.getCar();
SExpression listOneCdr = listOne.getCdr();
SExpression listTwoCdr = listTwo.getCdr();
if (!isListPair(firstArgument, secondArgument))
return equal(firstArgument, secondArgument);
SExpression carEqual = call(new Cons(listOneCar, LIST.makeList(listTwoCar)));
SExpression cdrEqual = call(new Cons(listOneCdr, LIST.makeList(listTwoCdr)));
Cons listOne = (Cons) firstArgument;
Cons listTwo = (Cons) secondArgument;
SExpression listOneCar = listOne.getCar();
SExpression listTwoCar = listTwo.getCar();
SExpression listOneCdr = listOne.getCdr();
SExpression listTwoCdr = listTwo.getCdr();
return (((carEqual == Symbol.T) && (cdrEqual == Symbol.T)) ? Symbol.T : Nil.getInstance());
}
SExpression carEqual = callRecursive(makeArgumentList(listOneCar, listTwoCar));
SExpression cdrEqual = callRecursive(makeArgumentList(listOneCdr, listTwoCdr));
return ((argOne.toString().equals(argTwo.toString())) ? Symbol.T : Nil.getInstance());
return logicalConjunction(carEqual, cdrEqual);
}
private boolean isListPair(SExpression firstArgument, SExpression secondArgument) {
return firstArgument.consp() && secondArgument.consp();
}
private SExpression equal(SExpression firstArgument, SExpression secondArgument) {
return isEqual(firstArgument, secondArgument) ? Symbol.T : Nil.getInstance();
}
private boolean isEqual(SExpression firstArgument, SExpression secondArgument) {
return firstArgument.toString().equals(secondArgument.toString());
}
private Cons makeArgumentList(SExpression listOneCar, SExpression listTwoCar) {
return new Cons(listOneCar, LIST.makeList(listTwoCar));
}
private SExpression logicalConjunction(SExpression carEqual, SExpression cdrEqual) {
return bothAreTrue(carEqual, cdrEqual) ? Symbol.T : Nil.getInstance();
}
private boolean bothAreTrue(SExpression carEqual, SExpression cdrEqual) {
return (carEqual == Symbol.T) && (cdrEqual == Symbol.T);
}
}

View File

@ -9,39 +9,62 @@ import function.ArgumentValidator.*;
public class EQUALTester {
@Test
public void testCarWithNil() {
String input = "(car nil)";
public void testEqualWithTwoEqualAtoms() {
String input = "(equal 'a 'a)";
assertSExpressionsMatch(evaluateString(input), parseString("()"));
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testCarWithList() {
String input = "(car '(1 2 3))";
public void testEqualWithTwoUnequalAtoms() {
String input = "(equal 'a 'b)";
assertSExpressionsMatch(evaluateString(input), parseString("1"));
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testNestedCarWithList() {
String input = "(car (car '((1 2) 3)))";
public void testEqualWithAtomAndList() {
String input = "(equal \"string\" '(m i k e))";
assertSExpressionsMatch(evaluateString(input), parseString("1"));
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test(expected = BadArgumentTypeException.class)
public void testCarWithNonList() {
evaluateString("(car 'x)");
@Test
public void testEqualWithListAndAtom() {
String input = "(equal '(m i k e) \"string\")";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testEqualWithTwoEqualLists() {
String input = "(equal '(1 2 3) '(1 2 3))";
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testEqualWithTwoUnequalLists() {
String input = "(equal '(1 2 3) '(1 3 3))";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testEqualWithTwoEqualNestedLists() {
String input = "(equal '(1 ((2) 3)) '(1 ((2) 3)))";
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test(expected = TooManyArgumentsException.class)
public void testCarWithTooManyArguments() {
evaluateString("(car '(1 2) '(1 2) \"oh\")");
public void testEqualWithTooManyArguments() {
evaluateString("(equal 1 2 3)");
}
@Test(expected = TooFewArgumentsException.class)
public void testCarWithTooFewArguments() {
evaluateString("(car)");
public void testEqualWithTooFewArguments() {
evaluateString("(equal 1)");
}
}