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; package function.builtin;
import function.LispFunction; import function.*;
import sexpression.*; import sexpression.*;
/**
* <code>EQUAL</code> represents the EQUAL function in Lisp.
*/
public class EQUAL extends LispFunction { public class EQUAL extends LispFunction {
// The number of arguments that EQUAL takes. private ArgumentValidator argumentValidator;
private static final int NUM_ARGS = 2;
public SExpression call(Cons argList) { public EQUAL() {
// retrieve the number of arguments passed to EQUAL this.argumentValidator = new ArgumentValidator("EQUAL");
int argListLength = LENGTH.getLength(argList); 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;
throw new RuntimeException(errMsg);
} }
SExpression argOne = argList.getCar(); // first argument public SExpression call(Cons argumentList) {
Cons cdr = (Cons) argList.getCdr(); argumentValidator.validate(argumentList);
SExpression argTwo = cdr.getCar(); // second argumnet
if (argOne.consp() && argTwo.consp()) { return callRecursive(argumentList);
Cons listOne = (Cons) argOne; }
Cons listTwo = (Cons) argTwo;
private SExpression callRecursive(Cons argumentList) {
Cons cdr = (Cons) argumentList.getCdr();
SExpression firstArgument = argumentList.getCar();
SExpression secondArgument = cdr.getCar();
if (!isListPair(firstArgument, secondArgument))
return equal(firstArgument, secondArgument);
Cons listOne = (Cons) firstArgument;
Cons listTwo = (Cons) secondArgument;
SExpression listOneCar = listOne.getCar(); SExpression listOneCar = listOne.getCar();
SExpression listTwoCar = listTwo.getCar(); SExpression listTwoCar = listTwo.getCar();
SExpression listOneCdr = listOne.getCdr(); SExpression listOneCdr = listOne.getCdr();
SExpression listTwoCdr = listTwo.getCdr(); SExpression listTwoCdr = listTwo.getCdr();
SExpression carEqual = call(new Cons(listOneCar, LIST.makeList(listTwoCar))); SExpression carEqual = callRecursive(makeArgumentList(listOneCar, listTwoCar));
SExpression cdrEqual = call(new Cons(listOneCdr, LIST.makeList(listTwoCdr))); SExpression cdrEqual = callRecursive(makeArgumentList(listOneCdr, listTwoCdr));
return (((carEqual == Symbol.T) && (cdrEqual == Symbol.T)) ? Symbol.T : Nil.getInstance()); return logicalConjunction(carEqual, cdrEqual);
} }
return ((argOne.toString().equals(argTwo.toString())) ? Symbol.T : Nil.getInstance()); 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 { public class EQUALTester {
@Test @Test
public void testCarWithNil() { public void testEqualWithTwoEqualAtoms() {
String input = "(car nil)"; String input = "(equal 'a 'a)";
assertSExpressionsMatch(evaluateString(input), parseString("()")); assertSExpressionsMatch(evaluateString(input), parseString("t"));
} }
@Test @Test
public void testCarWithList() { public void testEqualWithTwoUnequalAtoms() {
String input = "(car '(1 2 3))"; String input = "(equal 'a 'b)";
assertSExpressionsMatch(evaluateString(input), parseString("1")); assertSExpressionsMatch(evaluateString(input), parseString("nil"));
} }
@Test @Test
public void testNestedCarWithList() { public void testEqualWithAtomAndList() {
String input = "(car (car '((1 2) 3)))"; String input = "(equal \"string\" '(m i k e))";
assertSExpressionsMatch(evaluateString(input), parseString("1")); assertSExpressionsMatch(evaluateString(input), parseString("nil"));
} }
@Test(expected = BadArgumentTypeException.class) @Test
public void testCarWithNonList() { public void testEqualWithListAndAtom() {
evaluateString("(car 'x)"); 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) @Test(expected = TooManyArgumentsException.class)
public void testCarWithTooManyArguments() { public void testEqualWithTooManyArguments() {
evaluateString("(car '(1 2) '(1 2) \"oh\")"); evaluateString("(equal 1 2 3)");
} }
@Test(expected = TooFewArgumentsException.class) @Test(expected = TooFewArgumentsException.class)
public void testCarWithTooFewArguments() { public void testEqualWithTooFewArguments() {
evaluateString("(car)"); evaluateString("(equal 1)");
} }
} }