package function.builtin.special; import static sexpression.Nil.NIL; import static testutil.TestUtilities.*; import org.junit.*; import function.ArgumentValidator.*; import function.builtin.EVAL.UndefinedSymbolException; import sexpression.*; import table.ExecutionContext; public class LETTester { private ExecutionContext executionContext; public LETTester() { this.executionContext = ExecutionContext.getInstance(); } @Before public void setUp() { executionContext.clearContext(); } @After public void tearDown() { executionContext.clearContext(); } @Test public void simpleLet() { String input = "(let ((x 1)) x)"; assertSExpressionsMatch(new LispNumber("1"), evaluateString(input)); } @Test public void emptyLet_ReturnsNil() { String input = "(let ())"; assertSExpressionsMatch(NIL, evaluateString(input)); } @Test public void letWithSymbolsOnly_SetsValuesToNil() { String input = "(let ((x) (y)) (list x y))"; assertSExpressionsMatch(new Cons(NIL, new Cons(NIL, NIL)), evaluateString(input)); } @Test public void letWithSetf_DoesNotAlterGlobalVariable() { String before = "(setq x 22)"; String input = "(let ((x 1)) x)"; String after = "x"; assertSExpressionsMatch(new LispNumber("22"), evaluateString(before)); assertSExpressionsMatch(new LispNumber("1"), evaluateString(input)); assertSExpressionsMatch(new LispNumber("22"), evaluateString(after)); } @Test public void letWithNestedSetf_DoesNotAlterGlobalVariable() { String before = "(setq x 22)"; String input = "(let ((x 33)) (setq x 44) x)"; String after = "x"; assertSExpressionsMatch(new LispNumber("22"), evaluateString(before)); assertSExpressionsMatch(new LispNumber("44"), evaluateString(input)); assertSExpressionsMatch(new LispNumber("22"), evaluateString(after)); } @Test public void nestedLet() { String input = "(let ((x 1)) (let ((y (+ 1 x))) y))"; assertSExpressionsMatch(new LispNumber("2"), evaluateString(input)); } @Test public void nestedLetWithGlobals() { String before = "(setq x 92)"; String input = "(let ((x 1)) (let ((y (+ 1 x))) y))"; String after = "x"; assertSExpressionsMatch(new LispNumber("92"), evaluateString(before)); assertSExpressionsMatch(new LispNumber("2"), evaluateString(input)); assertSExpressionsMatch(new LispNumber("92"), evaluateString(after)); } @Test public void alterGlobalVariableFromLet() { String before = "(setq x 1)"; String input = "(let ((y 1)) (setq x 2))"; String after = "x"; assertSExpressionsMatch(new LispNumber("1"), evaluateString(before)); assertSExpressionsMatch(new LispNumber("2"), evaluateString(input)); assertSExpressionsMatch(new LispNumber("2"), evaluateString(after)); } @Test public void accessGlobalVariableFromLet() { String before = "(setq x 1)"; String input = "(let () x)"; assertSExpressionsMatch(new LispNumber("1"), evaluateString(before)); assertSExpressionsMatch(new LispNumber("1"), evaluateString(input)); } @Test(expected = UndefinedSymbolException.class) public void letDoesNotSetGlobalVariable() { String input = "(let ((x 1)) nil)"; evaluateString(input); evaluateString("x"); } @Test(expected = BadArgumentTypeException.class) public void letWithNonList() { evaluateString("(let a)"); } @Test(expected = BadArgumentTypeException.class) public void letWithNoPairs() { evaluateString("(let (a))"); } @Test(expected = TooFewArgumentsException.class) public void letWithTooFewItemsInPair() { evaluateString("(let (()))"); } @Test(expected = TooManyArgumentsException.class) public void letWithTooManyItemsInPair() { evaluateString("(let ((a b c)))"); } @Test(expected = BadArgumentTypeException.class) public void letWithNonSymbolInPair() { evaluateString("(let ((1 b)))"); } @Test(expected = TooFewArgumentsException.class) public void letWithTooFewArguments() { evaluateString("(let)"); } @Test(expected = DottedArgumentListException.class) public void letWithDottedArgumentList() { evaluateString("(apply 'let (cons 'a 'b))"); } @Test(expected = DottedArgumentListException.class) public void letWithDottedPairList() { evaluateString("(apply 'let (cons (cons 'a 'b) nil))"); } @Test(expected = DottedArgumentListException.class) public void letWithDottedPair() { evaluateString("(apply 'let (cons (cons (cons 'a 'b) nil) nil))"); } @Test(expected = UndefinedSymbolException.class) public void letEvaluatesSymbolsInParallel() { String input = "(let ((x 1) (y (+ x 1))) (+ x y))"; assertSExpressionsMatch(new LispNumber("2"), evaluateString(input)); } }