package function.builtin; import static sexpression.Nil.NIL; import static sexpression.Symbol.T; import static testutil.TestUtilities.assertIsErrorWithMessage; import static testutil.TestUtilities.assertSExpressionsMatch; import static testutil.TestUtilities.makeList; import org.junit.Test; import function.ArgumentValidator.DottedArgumentListException; import function.builtin.BackquoteEvaluator.AtSignNotInCommaException; import function.builtin.BackquoteEvaluator.AtSignNotListException; import function.builtin.BackquoteEvaluator.NestedAtSignException; import function.builtin.BackquoteEvaluator.NestedCommaException; import sexpression.AtSignExpression; import sexpression.BackquoteExpression; import sexpression.CommaExpression; import sexpression.Cons; import sexpression.LispNumber; import sexpression.LispString; import sexpression.SExpression; import sexpression.Symbol; public class BackquoteEvaluatorTest { private BackquoteEvaluator createBackquoteEvaluator(SExpression expression) { return new BackquoteEvaluator(new BackquoteExpression(expression)); } @Test public void evaluateNil() { BackquoteEvaluator evaluator = createBackquoteEvaluator(NIL); assertSExpressionsMatch(NIL, evaluator.evaluate()); } @Test public void evaluateNumber() { SExpression input = new LispNumber("99"); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); assertSExpressionsMatch(input, evaluator.evaluate()); } @Test public void evaluateList() { SExpression input = makeList(new LispNumber("1"), new LispNumber("99")); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); assertSExpressionsMatch(input, evaluator.evaluate()); } @Test public void evaluateComma() { SExpression input = new CommaExpression(makeList(new Symbol("+"), new LispNumber("1"), new LispNumber("9"))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); assertSExpressionsMatch(new LispNumber("10"), evaluator.evaluate()); } @Test public void evaluateListWithComma() { SExpression input = makeList(new CommaExpression(makeList(new Symbol("+"), new LispNumber("1"), new LispNumber("9")))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); assertSExpressionsMatch(makeList(new LispNumber("10")), evaluator.evaluate()); } @Test(expected = NestedCommaException.class) public void evaluateListWithNestedComma() { SExpression input = makeList(new CommaExpression(new CommaExpression(new Symbol("+")))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test(expected = AtSignNotInCommaException.class) public void evaluateListWithNoCommaPrecedingAtSign() { SExpression input = makeList(new AtSignExpression(makeList(new Symbol("+")))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test(expected = AtSignNotInCommaException.class) public void evaluateAtSign() { SExpression input = new AtSignExpression(makeList(new Symbol("+"))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test(expected = NestedAtSignException.class) public void evaluateListWithNestedAtSigns() { SExpression input = makeList(new CommaExpression(new AtSignExpression(new AtSignExpression(makeList(new Symbol("+")))))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test(expected = NestedCommaException.class) public void evaluateListWithCommaAfterAtSign() { SExpression input = makeList(new CommaExpression(new AtSignExpression(new CommaExpression(makeList(new Symbol("+")))))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test public void evaluateListWithAtSign() { SExpression input = makeList(new CommaExpression(new AtSignExpression(makeList(new Symbol("LIST"), new LispNumber("1"), new LispNumber("9"))))); SExpression expected = makeList(new LispNumber("1"), new LispNumber("9")); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); assertSExpressionsMatch(expected, evaluator.evaluate()); } @Test(expected = AtSignNotListException.class) public void atSignDoesNotEvaluateToList() { SExpression input = makeList(new CommaExpression(new AtSignExpression(new LispNumber("1")))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test public void evaluateListWithCommasAndAtSign() { Cons list1 = makeList(new Symbol("LIST"), new LispNumber("1"), new LispNumber("9")); Cons list2 = makeList(new Symbol("+"), new LispNumber("20"), new LispNumber("5")); Cons list3 = makeList(new Symbol("LIST"), new LispNumber("7"), new LispNumber("6")); SExpression input = makeList(new LispNumber("78"), new CommaExpression(new AtSignExpression(list1)), new CommaExpression(list2), new CommaExpression(list3), new LispString("\"sky\"")); SExpression expected = makeList(new LispNumber("78"), new LispNumber("1"), new LispNumber("9"), new LispNumber("25"), makeList(new LispNumber("7"), new LispNumber("6")), new LispString("\"sky\"")); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); assertSExpressionsMatch(expected, evaluator.evaluate()); } @Test(expected = DottedArgumentListException.class) public void evaluateDottedList() { BackquoteEvaluator evaluator = createBackquoteEvaluator(new Cons(T, T)); evaluator.evaluate(); } @Test(expected = DottedArgumentListException.class) public void atSignWithDottedList() { SExpression input = makeList(new CommaExpression(new AtSignExpression(makeList(new Symbol("CONS"), T, T)))); BackquoteEvaluator evaluator = createBackquoteEvaluator(input); evaluator.evaluate(); } @Test public void backquoteExceptionsHaveCorrectAttributes() { assertIsErrorWithMessage(new NestedCommaException()); assertIsErrorWithMessage(new NestedAtSignException()); assertIsErrorWithMessage(new AtSignNotInCommaException()); assertIsErrorWithMessage(new AtSignNotListException()); } }