package function.builtin.special; 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(); } @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.getInstance(), evaluateString(input)); } @Test public void letWithSetf_DoesNotAlterGlobalVariable() { String before = "(setf 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 = "(setf x 22)"; String input = "(let ((x 33)) (setf 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 = "(setf 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 = "(setf x 1)"; String input = "(let ((y 1)) (setf 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 = "(setf 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 testLetWithNonList() { evaluateString("(let a)"); } @Test(expected = BadArgumentTypeException.class) public void testLetWithNoPairs() { evaluateString("(let (a))"); } @Test(expected = TooFewArgumentsException.class) public void testLetWithTooFewItemsInPair() { evaluateString("(let ((a)))"); } @Test(expected = TooManyArgumentsException.class) public void testLetWithTooManyItemsInPair() { evaluateString("(let ((a b c)))"); } @Test(expected = BadArgumentTypeException.class) public void testLetWithNonSymbolInPair() { evaluateString("(let ((1 b)))"); } @Test(expected = TooFewArgumentsException.class) public void testLetWithTooFewArguments() { evaluateString("(let)"); } @Test(expected = DottedArgumentListException.class) public void testLetWithDottedArgumentList() { evaluateString("(apply 'let (cons 'a 'b))"); } @Test(expected = DottedArgumentListException.class) public void testLetWithDottedPairList() { evaluateString("(apply 'let (cons (cons 'a 'b) nil))"); } @Test(expected = DottedArgumentListException.class) public void testLetWithDottedPair() { evaluateString("(apply 'let (cons (cons (cons 'a 'b) nil) nil))"); } }